diff options
Diffstat (limited to 'src')
242 files changed, 15863 insertions, 12818 deletions
diff --git a/src/App.native.tsx b/src/App.native.tsx index eff8ab099..e825ffa00 100644 --- a/src/App.native.tsx +++ b/src/App.native.tsx @@ -5,7 +5,7 @@ import React, {useState, useEffect} from 'react' import {RootSiblingParent} from 'react-native-root-siblings' import * as SplashScreen from 'expo-splash-screen' import {GestureHandlerRootView} from 'react-native-gesture-handler' -import {QueryClientProvider} from '@tanstack/react-query' +import {PersistQueryClientProvider} from '@tanstack/react-query-persist-client' import { SafeAreaProvider, initialWindowMetrics, @@ -22,7 +22,11 @@ import {s} from 'lib/styles' import {Shell} from 'view/shell' import * as notifications from 'lib/notifications/notifications' import * as Toast from 'view/com/util/Toast' -import {queryClient} from 'lib/react-query' +import { + queryClient, + asyncStoragePersister, + dehydrateOptions, +} from 'lib/react-query' import {TestCtrls} from 'view/com/testing/TestCtrls' import {Provider as ShellStateProvider} from 'state/shell' import {Provider as ModalStateProvider} from 'state/modals' @@ -33,6 +37,7 @@ import {Provider as InvitesStateProvider} from 'state/invites' import {Provider as PrefsStateProvider} from 'state/preferences' import {Provider as LoggedOutViewProvider} from 'state/shell/logged-out' import {Provider as SelectedFeedProvider} from 'state/shell/selected-feed' +import {Provider as LabelDefsProvider} from '#/state/preferences/label-defs' import I18nProvider from './locale/i18nProvider' import { Provider as SessionProvider, @@ -79,21 +84,23 @@ function InnerApp() { // Resets the entire tree below when it changes: key={currentAccount?.did}> <StatsigProvider> - <LoggedOutViewProvider> - <SelectedFeedProvider> - <UnreadNotifsProvider> - <ThemeProvider theme={theme}> - {/* All components should be within this provider */} - <RootSiblingParent> - <GestureHandlerRootView style={s.h100pct}> - <TestCtrls /> - <Shell /> - </GestureHandlerRootView> - </RootSiblingParent> - </ThemeProvider> - </UnreadNotifsProvider> - </SelectedFeedProvider> - </LoggedOutViewProvider> + <LabelDefsProvider> + <LoggedOutViewProvider> + <SelectedFeedProvider> + <UnreadNotifsProvider> + <ThemeProvider theme={theme}> + {/* All components should be within this provider */} + <RootSiblingParent> + <GestureHandlerRootView style={s.h100pct}> + <TestCtrls /> + <Shell /> + </GestureHandlerRootView> + </RootSiblingParent> + </ThemeProvider> + </UnreadNotifsProvider> + </SelectedFeedProvider> + </LoggedOutViewProvider> + </LabelDefsProvider> </StatsigProvider> </React.Fragment> </Splash> @@ -118,7 +125,9 @@ function App() { * that is set up in the InnerApp component above. */ return ( - <QueryClientProvider client={queryClient}> + <PersistQueryClientProvider + client={queryClient} + persistOptions={{persister: asyncStoragePersister, dehydrateOptions}}> <SessionProvider> <ShellStateProvider> <PrefsStateProvider> @@ -140,7 +149,7 @@ function App() { </PrefsStateProvider> </ShellStateProvider> </SessionProvider> - </QueryClientProvider> + </PersistQueryClientProvider> ) } diff --git a/src/App.web.tsx b/src/App.web.tsx index eb2e42593..f47f763da 100644 --- a/src/App.web.tsx +++ b/src/App.web.tsx @@ -1,7 +1,7 @@ import 'lib/sentry' // must be near top import React, {useState, useEffect} from 'react' -import {QueryClientProvider} from '@tanstack/react-query' +import {PersistQueryClientProvider} from '@tanstack/react-query-persist-client' import {SafeAreaProvider} from 'react-native-safe-area-context' import {RootSiblingParent} from 'react-native-root-siblings' @@ -13,7 +13,11 @@ import {init as initPersistedState} from '#/state/persisted' import {Shell} from 'view/shell/index' import {ToastContainer} from 'view/com/util/Toast.web' import {ThemeProvider} from 'lib/ThemeContext' -import {queryClient} from 'lib/react-query' +import { + queryClient, + asyncStoragePersister, + dehydrateOptions, +} from 'lib/react-query' import {Provider as ShellStateProvider} from 'state/shell' import {Provider as ModalStateProvider} from 'state/modals' import {Provider as DialogStateProvider} from 'state/dialogs' @@ -23,6 +27,7 @@ import {Provider as InvitesStateProvider} from 'state/invites' import {Provider as PrefsStateProvider} from 'state/preferences' import {Provider as LoggedOutViewProvider} from 'state/shell/logged-out' import {Provider as SelectedFeedProvider} from 'state/shell/selected-feed' +import {Provider as LabelDefsProvider} from '#/state/preferences/label-defs' import I18nProvider from './locale/i18nProvider' import { Provider as SessionProvider, @@ -56,21 +61,23 @@ function InnerApp() { // Resets the entire tree below when it changes: key={currentAccount?.did}> <StatsigProvider> - <LoggedOutViewProvider> - <SelectedFeedProvider> - <UnreadNotifsProvider> - <ThemeProvider theme={theme}> - {/* All components should be within this provider */} - <RootSiblingParent> - <SafeAreaProvider> - <Shell /> - </SafeAreaProvider> - </RootSiblingParent> - <ToastContainer /> - </ThemeProvider> - </UnreadNotifsProvider> - </SelectedFeedProvider> - </LoggedOutViewProvider> + <LabelDefsProvider> + <LoggedOutViewProvider> + <SelectedFeedProvider> + <UnreadNotifsProvider> + <ThemeProvider theme={theme}> + {/* All components should be within this provider */} + <RootSiblingParent> + <SafeAreaProvider> + <Shell /> + </SafeAreaProvider> + </RootSiblingParent> + <ToastContainer /> + </ThemeProvider> + </UnreadNotifsProvider> + </SelectedFeedProvider> + </LoggedOutViewProvider> + </LabelDefsProvider> </StatsigProvider> </React.Fragment> </Alf> @@ -93,7 +100,9 @@ function App() { * that is set up in the InnerApp component above. */ return ( - <QueryClientProvider client={queryClient}> + <PersistQueryClientProvider + client={queryClient} + persistOptions={{persister: asyncStoragePersister, dehydrateOptions}}> <SessionProvider> <ShellStateProvider> <PrefsStateProvider> @@ -115,7 +124,7 @@ function App() { </PrefsStateProvider> </ShellStateProvider> </SessionProvider> - </QueryClientProvider> + </PersistQueryClientProvider> ) } diff --git a/src/Navigation.tsx b/src/Navigation.tsx index 8a9f69b5d..3d6a15c4e 100644 --- a/src/Navigation.tsx +++ b/src/Navigation.tsx @@ -46,7 +46,7 @@ import {SearchScreen} from './view/screens/Search' import {FeedsScreen} from './view/screens/Feeds' import {NotificationsScreen} from './view/screens/Notifications' import {ListsScreen} from './view/screens/Lists' -import {ModerationScreen} from './view/screens/Moderation' +import {ModerationScreen} from '#/screens/Moderation' import {ModerationModlistsScreen} from './view/screens/ModerationModlists' import {NotFoundScreen} from './view/screens/NotFound' import {SettingsScreen} from './view/screens/Settings' @@ -61,6 +61,7 @@ import {PostThreadScreen} from './view/screens/PostThread' import {PostLikedByScreen} from './view/screens/PostLikedBy' import {PostRepostedByScreen} from './view/screens/PostRepostedBy' import {Storybook} from './view/screens/Storybook' +import {DebugModScreen} from './view/screens/DebugMod' import {LogScreen} from './view/screens/Log' import {SupportScreen} from './view/screens/Support' import {PrivacyPolicyScreen} from './view/screens/PrivacyPolicy' @@ -78,7 +79,8 @@ import {createNativeStackNavigatorWithAuth} from './view/shell/createNativeStack import {msg} from '@lingui/macro' import {i18n, MessageDescriptor} from '@lingui/core' import HashtagScreen from '#/screens/Hashtag' -import {logEvent} from './lib/statsig/statsig' +import {ProfileLabelerLikedByScreen} from '#/screens/Profile/ProfileLabelerLikedBy' +import {logEvent, attachRouteToLogEvents} from './lib/statsig/statsig' const navigationRef = createNavigationContainerRef<AllNavigatorParams>() @@ -199,11 +201,21 @@ function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) { options={{title: title(msg`Liked by`)}} /> <Stack.Screen + name="ProfileLabelerLikedBy" + getComponent={() => ProfileLabelerLikedByScreen} + options={{title: title(msg`Liked by`)}} + /> + <Stack.Screen name="Debug" getComponent={() => Storybook} options={{title: title(msg`Storybook`), requireAuth: true}} /> <Stack.Screen + name="DebugMod" + getComponent={() => DebugModScreen} + options={{title: title(msg`Moderation states`), requireAuth: true}} + /> + <Stack.Screen name="Log" getComponent={() => LogScreen} options={{title: title(msg`Log`), requireAuth: true}} @@ -543,6 +555,7 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) { linking={LINKING} theme={theme} onReady={() => { + attachRouteToLogEvents(getCurrentRouteName) logModuleInitTime() onReady() }}> @@ -551,6 +564,10 @@ function RoutesContainer({children}: React.PropsWithChildren<{}>) { ) } +function getCurrentRouteName() { + return navigationRef.getCurrentRoute()?.name +} + /** * These helpers can be used from outside of the RoutesContainer * (eg in the state models). @@ -656,7 +673,9 @@ function logModuleInitTime() { performance.now() - global.__BUNDLE_START_TIME__, ) console.log(`Time to first paint: ${initMs} ms`) - logEvent('init', initMs) + logEvent('init', { + initMs, + }) if (__DEV__) { // This log is noisy, so keep false committed diff --git a/src/alf/atoms.ts b/src/alf/atoms.ts index fff3a4d8b..0b473ba90 100644 --- a/src/alf/atoms.ts +++ b/src/alf/atoms.ts @@ -1,3 +1,4 @@ +import {Platform} from 'react-native' import {web, native} from '#/alf/util/platform' import * as tokens from '#/alf/tokens' @@ -6,7 +7,7 @@ export const atoms = { * Positioning */ fixed: { - position: 'fixed', + position: Platform.select({web: 'fixed', native: 'absolute'}) as 'absolute', }, absolute: { position: 'absolute', @@ -49,6 +50,9 @@ export const atoms = { h_full: { height: '100%', }, + h_full_vh: web({ + height: '100vh', + }), /* * Border radius @@ -111,6 +115,12 @@ export const atoms = { flex_row: { flexDirection: 'row', }, + flex_col_reverse: { + flexDirection: 'column-reverse', + }, + flex_row_reverse: { + flexDirection: 'row-reverse', + }, flex_wrap: { flexWrap: 'wrap', }, @@ -236,6 +246,9 @@ export const atoms = { font_normal: { fontWeight: tokens.fontWeight.normal, }, + font_semibold: { + fontWeight: '500', + }, font_bold: { fontWeight: tokens.fontWeight.semibold, }, @@ -521,6 +534,10 @@ export const atoms = { /* * Margin */ + mx_auto: { + marginLeft: 'auto', + marginRight: 'auto', + }, m_2xs: { margin: tokens.space._2xs, }, diff --git a/src/alf/index.tsx b/src/alf/index.tsx index 27738e91d..f0a0ede7a 100644 --- a/src/alf/index.tsx +++ b/src/alf/index.tsx @@ -16,6 +16,7 @@ type BreakpointName = keyof typeof breakpoints const breakpoints: { [key: string]: number } = { + gtPhone: 500, gtMobile: 800, gtTablet: 1300, } @@ -26,6 +27,7 @@ function getActiveBreakpoints({width}: {width: number}) { return { active: active[active.length - 1], + gtPhone: active.includes('gtPhone'), gtMobile: active.includes('gtMobile'), gtTablet: active.includes('gtTablet'), } @@ -39,6 +41,7 @@ export const Context = React.createContext<{ theme: themes.Theme breakpoints: { active: BreakpointName | undefined + gtPhone: boolean gtMobile: boolean gtTablet: boolean } @@ -47,6 +50,7 @@ export const Context = React.createContext<{ theme: themes.light, breakpoints: { active: undefined, + gtPhone: false, gtMobile: false, gtTablet: false, }, diff --git a/src/alf/tokens.ts b/src/alf/tokens.ts index b1468f461..4045c831c 100644 --- a/src/alf/tokens.ts +++ b/src/alf/tokens.ts @@ -12,6 +12,9 @@ export const dimScale = generateScale(12, 100) export const color = { trueBlack: '#000000', + temp_purple: 'rgb(105 0 255)', + temp_purple_dark: 'rgb(83 0 202)', + gray_0: `hsl(${BLUE_HUE}, 20%, ${scale[14]}%)`, gray_25: `hsl(${BLUE_HUE}, 20%, ${scale[13]}%)`, gray_50: `hsl(${BLUE_HUE}, 20%, ${scale[12]}%)`, diff --git a/src/components/Button.tsx b/src/components/Button.tsx index d3bf73cc3..0e22944a3 100644 --- a/src/components/Button.tsx +++ b/src/components/Button.tsx @@ -15,6 +15,7 @@ import LinearGradient from 'react-native-linear-gradient' import {useTheme, atoms as a, tokens, android, flatten} from '#/alf' import {Props as SVGIconProps} from '#/components/icons/common' +import {normalizeTextStyles} from '#/components/Typography' export type ButtonVariant = 'solid' | 'outline' | 'ghost' | 'gradient' export type ButtonColor = @@ -139,7 +140,7 @@ export function Button({ })) }, [setState]) - const {baseStyles, hoverStyles, focusStyles} = React.useMemo(() => { + const {baseStyles, hoverStyles} = React.useMemo(() => { const baseStyles: ViewStyle[] = [] const hoverStyles: ViewStyle[] = [] const light = t.name === 'light' @@ -191,14 +192,14 @@ export function Button({ if (variant === 'solid') { if (!disabled) { baseStyles.push({ - backgroundColor: t.palette.contrast_50, + backgroundColor: t.palette.contrast_25, }) hoverStyles.push({ - backgroundColor: t.palette.contrast_100, + backgroundColor: t.palette.contrast_50, }) } else { baseStyles.push({ - backgroundColor: t.palette.contrast_200, + backgroundColor: t.palette.contrast_100, }) } } else if (variant === 'outline') { @@ -308,12 +309,6 @@ export function Button({ return { baseStyles, hoverStyles, - focusStyles: [ - ...hoverStyles, - { - outline: 0, - } as ViewStyle, - ], } }, [t, variant, color, size, shape, disabled]) @@ -376,10 +371,8 @@ export function Button({ a.flex_row, a.align_center, a.justify_center, - a.justify_center, flattenedBaseStyles, ...(state.hovered || state.pressed ? hoverStyles : []), - ...(state.focused ? focusStyles : []), flatten(style), ]} onPressIn={onPressIn} @@ -398,7 +391,7 @@ export function Button({ ]}> <LinearGradient colors={ - state.hovered || state.pressed || state.focused + state.hovered || state.pressed ? gradientHoverColors : gradientColors } @@ -527,7 +520,14 @@ export function ButtonText({children, style, ...rest}: ButtonTextProps) { const textStyles = useSharedButtonTextStyles() return ( - <Text {...rest} style={[a.font_bold, a.text_center, textStyles, style]}> + <Text + {...rest} + style={normalizeTextStyles([ + a.font_bold, + a.text_center, + textStyles, + style, + ])}> {children} </Text> ) diff --git a/src/components/Dialog/index.tsx b/src/components/Dialog/index.tsx index f0e7b7e82..0da2919c5 100644 --- a/src/components/Dialog/index.tsx +++ b/src/components/Dialog/index.tsx @@ -23,6 +23,7 @@ import { DialogInnerProps, } from '#/components/Dialog/types' import {Context} from '#/components/Dialog/context' +import {isNative} from 'platform/detection' export {useDialogControl, useDialogContext} from '#/components/Dialog/context' export * from '#/components/Dialog/types' @@ -75,6 +76,7 @@ export function Outer({ control, onClose, nativeOptions, + testID, }: React.PropsWithChildren<DialogOuterProps>) { const t = useTheme() const sheet = React.useRef<BottomSheet>(null) @@ -145,7 +147,8 @@ export function Outer({ accessibilityViewIsModal // Android importantForAccessibility="yes" - style={[a.absolute, a.inset_0]}> + style={[a.absolute, a.inset_0]} + testID={testID}> <BottomSheet enableDynamicSizing={!hasSnapPoints} enablePanDownToClose @@ -219,7 +222,8 @@ export function ScrollableInner({children, style}: DialogInnerProps) { borderTopRightRadius: 40, }, flatten(style), - ]}> + ]} + contentContainerStyle={isNative ? a.pb_4xl : undefined}> {children} <View style={{height: insets.bottom + a.pt_5xl.paddingTop}} /> </BottomSheetScrollView> diff --git a/src/components/Dialog/index.web.tsx b/src/components/Dialog/index.web.tsx index 3a7f73342..038f6295a 100644 --- a/src/components/Dialog/index.web.tsx +++ b/src/components/Dialog/index.web.tsx @@ -99,7 +99,7 @@ export function Outer({ style={[ web(a.fixed), a.inset_0, - {opacity: 0.5, backgroundColor: t.palette.black}, + {opacity: 0.8, backgroundColor: t.palette.black}, ]} /> )} diff --git a/src/components/Dialog/types.ts b/src/components/Dialog/types.ts index 4fc60ec39..b1a46f853 100644 --- a/src/components/Dialog/types.ts +++ b/src/components/Dialog/types.ts @@ -1,5 +1,5 @@ import React from 'react' -import type {AccessibilityProps} from 'react-native' +import type {AccessibilityProps, GestureResponderEvent} from 'react-native' import {BottomSheetProps} from '@gorhom/bottom-sheet' import {ViewStyleProp} from '#/alf' @@ -10,9 +10,15 @@ type A11yProps = Required<AccessibilityProps> * Mutated by useImperativeHandle to provide a public API for controlling the * dialog. The methods here will actually become the handlers defined within * the `Dialog.Outer` component. + * + * `Partial<GestureResponderEvent>` here allows us to add this directly to the + * `onPress` prop of a button, for example. If this type was not added, we + * would need to create a function to wrap `.open()` with. */ export type DialogControlRefProps = { - open: (options?: DialogControlOpenOptions) => void + open: ( + options?: DialogControlOpenOptions & Partial<GestureResponderEvent>, + ) => void close: (callback?: () => void) => void } @@ -46,6 +52,7 @@ export type DialogOuterProps = { sheet?: Omit<BottomSheetProps, 'children'> } webOptions?: {} + testID?: string } type DialogInnerPropsBase<T> = React.PropsWithChildren<ViewStyleProp> & T diff --git a/src/components/Error.tsx b/src/components/Error.tsx new file mode 100644 index 000000000..1dbf68284 --- /dev/null +++ b/src/components/Error.tsx @@ -0,0 +1,90 @@ +import React from 'react' + +import {CenteredView} from 'view/com/util/Views' +import {atoms as a, useBreakpoints, useTheme} from '#/alf' +import {Text} from '#/components/Typography' +import {View} from 'react-native' +import {Button} from '#/components/Button' +import {useNavigation} from '@react-navigation/core' +import {NavigationProp} from 'lib/routes/types' +import {StackActions} from '@react-navigation/native' +import {router} from '#/routes' + +export function Error({ + title, + message, + onRetry, +}: { + title?: string + message?: string + onRetry?: () => unknown +}) { + const navigation = useNavigation<NavigationProp>() + const t = useTheme() + const {gtMobile} = useBreakpoints() + + const canGoBack = navigation.canGoBack() + const onGoBack = React.useCallback(() => { + if (canGoBack) { + navigation.goBack() + } else { + navigation.navigate('HomeTab') + + // Checking the state for routes ensures that web doesn't encounter errors while going back + if (navigation.getState()?.routes) { + navigation.dispatch(StackActions.push(...router.matchPath('/'))) + } else { + navigation.navigate('HomeTab') + navigation.dispatch(StackActions.popToTop()) + } + } + }, [navigation, canGoBack]) + + return ( + <CenteredView + style={[ + a.flex_1, + a.align_center, + !gtMobile ? a.justify_between : a.gap_5xl, + t.atoms.border_contrast_low, + {paddingTop: 175, paddingBottom: 110}, + ]} + sideBorders> + <View style={[a.w_full, a.align_center, a.gap_lg]}> + <Text style={[a.font_bold, a.text_3xl]}>{title}</Text> + <Text + style={[ + a.text_md, + a.text_center, + t.atoms.text_contrast_high, + {lineHeight: 1.4}, + gtMobile && {width: 450}, + ]}> + {message} + </Text> + </View> + <View style={[a.gap_md, gtMobile ? {width: 350} : [a.w_full, a.px_lg]]}> + {onRetry && ( + <Button + variant="solid" + color="primary" + label="Click here" + onPress={onRetry} + size="large" + style={[a.rounded_sm, a.overflow_hidden, {paddingVertical: 10}]}> + Retry + </Button> + )} + <Button + variant="solid" + color={onRetry ? 'secondary' : 'primary'} + label="Click here" + onPress={onGoBack} + size="large" + style={[a.rounded_sm, a.overflow_hidden, {paddingVertical: 10}]}> + Go Back + </Button> + </View> + </CenteredView> + ) +} diff --git a/src/components/GradientFill.tsx b/src/components/GradientFill.tsx new file mode 100644 index 000000000..dc14aa72b --- /dev/null +++ b/src/components/GradientFill.tsx @@ -0,0 +1,27 @@ +import React from 'react' +import LinearGradient from 'react-native-linear-gradient' + +import {atoms as a, tokens} from '#/alf' + +export function GradientFill({ + gradient, +}: { + gradient: + | typeof tokens.gradients.sky + | typeof tokens.gradients.midnight + | typeof tokens.gradients.sunrise + | typeof tokens.gradients.sunset + | typeof tokens.gradients.bonfire + | typeof tokens.gradients.summer + | typeof tokens.gradients.nordic +}) { + return ( + <LinearGradient + colors={gradient.values.map(c => c[1])} + locations={gradient.values.map(c => c[0])} + start={{x: 0, y: 0}} + end={{x: 1, y: 1}} + style={[a.absolute, a.inset_0]} + /> + ) +} diff --git a/src/components/LabelingServiceCard/index.tsx b/src/components/LabelingServiceCard/index.tsx new file mode 100644 index 000000000..f924f0f59 --- /dev/null +++ b/src/components/LabelingServiceCard/index.tsx @@ -0,0 +1,182 @@ +import React from 'react' +import {View} from 'react-native' +import {msg, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {AppBskyLabelerDefs} from '@atproto/api' + +import {getLabelingServiceTitle} from '#/lib/moderation' +import {Link as InternalLink, LinkProps} from '#/components/Link' +import {Text} from '#/components/Typography' +import {useLabelerInfoQuery} from '#/state/queries/labeler' +import {atoms as a, useTheme, ViewStyleProp} from '#/alf' +import {RichText} from '#/components/RichText' +import {ChevronRight_Stroke2_Corner0_Rounded as ChevronRight} from '../icons/Chevron' +import {UserAvatar} from '#/view/com/util/UserAvatar' +import {sanitizeHandle} from '#/lib/strings/handles' +import {pluralize} from '#/lib/strings/helpers' + +type LabelingServiceProps = { + labeler: AppBskyLabelerDefs.LabelerViewDetailed +} + +export function Outer({ + children, + style, +}: React.PropsWithChildren<ViewStyleProp>) { + return ( + <View + style={[ + a.flex_row, + a.gap_md, + a.w_full, + a.p_lg, + a.pr_md, + a.overflow_hidden, + style, + ]}> + {children} + </View> + ) +} + +export function Avatar({avatar}: {avatar?: string}) { + return <UserAvatar type="labeler" size={40} avatar={avatar} /> +} + +export function Title({value}: {value: string}) { + return <Text style={[a.text_md, a.font_bold]}>{value}</Text> +} + +export function Description({value, handle}: {value?: string; handle: string}) { + return value ? ( + <Text numberOfLines={2}> + <RichText value={value} style={[]} /> + </Text> + ) : ( + <Text> + <Trans>By {sanitizeHandle(handle, '@')}</Trans> + </Text> + ) +} + +export function LikeCount({count}: {count: number}) { + const t = useTheme() + return ( + <Text + style={[ + a.mt_sm, + a.text_sm, + t.atoms.text_contrast_medium, + {fontWeight: '500'}, + ]}> + <Trans> + Liked by {count} {pluralize(count, 'user')} + </Trans> + </Text> + ) +} + +export function Content({children}: React.PropsWithChildren<{}>) { + const t = useTheme() + + return ( + <View + style={[ + a.flex_1, + a.flex_row, + a.gap_md, + a.align_center, + a.justify_between, + ]}> + <View style={[a.gap_xs, a.flex_1]}>{children}</View> + + <ChevronRight size="md" style={[a.z_10, t.atoms.text_contrast_low]} /> + </View> + ) +} + +/** + * The canonical view for a labeling service. Use this or compose your own. + */ +export function Default({ + labeler, + style, +}: LabelingServiceProps & ViewStyleProp) { + return ( + <Outer style={style}> + <Avatar avatar={labeler.creator.avatar} /> + <Content> + <Title + value={getLabelingServiceTitle({ + displayName: labeler.creator.displayName, + handle: labeler.creator.handle, + })} + /> + <Description + value={labeler.creator.description} + handle={labeler.creator.handle} + /> + {labeler.likeCount ? <LikeCount count={labeler.likeCount} /> : null} + </Content> + </Outer> + ) +} + +export function Link({ + children, + labeler, +}: LabelingServiceProps & Pick<LinkProps, 'children'>) { + const {_} = useLingui() + + return ( + <InternalLink + to={{ + screen: 'Profile', + params: { + name: labeler.creator.handle, + }, + }} + label={_( + msg`View the labeling service provided by @${labeler.creator.handle}`, + )}> + {children} + </InternalLink> + ) +} + +// TODO not finished yet +export function DefaultSkeleton() { + return ( + <View> + <Text>Loading</Text> + </View> + ) +} + +export function Loader({ + did, + loading: LoadingComponent = DefaultSkeleton, + error: ErrorComponent, + component: Component, +}: { + did: string + loading?: React.ComponentType<{}> + error?: React.ComponentType<{error: string}> + component: React.ComponentType<{ + labeler: AppBskyLabelerDefs.LabelerViewDetailed + }> +}) { + const {isLoading, data, error} = useLabelerInfoQuery({did}) + + return isLoading ? ( + LoadingComponent ? ( + <LoadingComponent /> + ) : null + ) : error || !data ? ( + ErrorComponent ? ( + <ErrorComponent error={error?.message || 'Unknown error'} /> + ) : null + ) : ( + <Component labeler={data} /> + ) +} diff --git a/src/components/LikedByList.tsx b/src/components/LikedByList.tsx new file mode 100644 index 000000000..bd1213639 --- /dev/null +++ b/src/components/LikedByList.tsx @@ -0,0 +1,109 @@ +import React from 'react' +import {View} from 'react-native' +import {AppBskyFeedGetLikes as GetLikes} from '@atproto/api' +import {Trans} from '@lingui/macro' + +import {logger} from '#/logger' +import {List} from '#/view/com/util/List' +import {ProfileCardWithFollowBtn} from '#/view/com/profile/ProfileCard' +import {useResolveUriQuery} from '#/state/queries/resolve-uri' +import {useLikedByQuery} from '#/state/queries/post-liked-by' +import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender' +import {ListFooter} from '#/components/Lists' + +import {atoms as a, useTheme} from '#/alf' +import {Loader} from '#/components/Loader' +import {Text} from '#/components/Typography' + +export function LikedByList({uri}: {uri: string}) { + const t = useTheme() + const [isPTRing, setIsPTRing] = React.useState(false) + const { + data: resolvedUri, + error: resolveError, + isFetching: isFetchingResolvedUri, + } = useResolveUriQuery(uri) + const { + data, + isFetching, + isFetched, + isRefetching, + hasNextPage, + fetchNextPage, + isError, + error: likedByError, + refetch, + } = useLikedByQuery(resolvedUri?.uri) + const likes = React.useMemo(() => { + if (data?.pages) { + return data.pages.flatMap(page => page.likes) + } + return [] + }, [data]) + const initialNumToRender = useInitialNumToRender() + const error = resolveError || likedByError + + const onRefresh = React.useCallback(async () => { + setIsPTRing(true) + try { + await refetch() + } catch (err) { + logger.error('Failed to refresh likes', {message: err}) + } + setIsPTRing(false) + }, [refetch, setIsPTRing]) + + const onEndReached = React.useCallback(async () => { + if (isFetching || !hasNextPage || isError) return + try { + await fetchNextPage() + } catch (err) { + logger.error('Failed to load more likes', {message: err}) + } + }, [isFetching, hasNextPage, isError, fetchNextPage]) + + const renderItem = React.useCallback(({item}: {item: GetLikes.Like}) => { + return ( + <ProfileCardWithFollowBtn key={item.actor.did} profile={item.actor} /> + ) + }, []) + + if (isFetchingResolvedUri || !isFetched) { + return ( + <View style={[a.w_full, a.align_center, a.p_lg]}> + <Loader size="xl" /> + </View> + ) + } + + return likes.length ? ( + <List + data={likes} + keyExtractor={item => item.actor.did} + refreshing={isPTRing} + onRefresh={onRefresh} + onEndReached={onEndReached} + onEndReachedThreshold={3} + renderItem={renderItem} + initialNumToRender={initialNumToRender} + ListFooterComponent={() => ( + <ListFooter + isFetching={isFetching && !isRefetching} + isError={isError} + error={error ? error.toString() : undefined} + onRetry={fetchNextPage} + /> + )} + /> + ) : ( + <View style={[a.p_lg]}> + <View style={[a.p_lg, a.rounded_sm, t.atoms.bg_contrast_25]}> + <Text style={[a.text_md, a.leading_snug]}> + <Trans> + Nobody has liked this yet. Maybe you should be the first! + </Trans> + </Text> + </View> + </View> + ) +} diff --git a/src/components/LikesDialog.tsx b/src/components/LikesDialog.tsx new file mode 100644 index 000000000..94a3f27e2 --- /dev/null +++ b/src/components/LikesDialog.tsx @@ -0,0 +1,131 @@ +import React, {useMemo, useCallback} from 'react' +import {ActivityIndicator, FlatList, View} from 'react-native' +import {msg, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {AppBskyFeedGetLikes as GetLikes} from '@atproto/api' + +import {useResolveUriQuery} from '#/state/queries/resolve-uri' +import {useLikedByQuery} from '#/state/queries/post-liked-by' +import {cleanError} from '#/lib/strings/errors' +import {logger} from '#/logger' + +import {atoms as a, useTheme} from '#/alf' +import {Text} from '#/components/Typography' +import * as Dialog from '#/components/Dialog' +import {ErrorMessage} from '#/view/com/util/error/ErrorMessage' +import {ProfileCardWithFollowBtn} from '#/view/com/profile/ProfileCard' +import {Loader} from '#/components/Loader' + +interface LikesDialogProps { + control: Dialog.DialogOuterProps['control'] + uri: string +} + +export function LikesDialog(props: LikesDialogProps) { + return ( + <Dialog.Outer control={props.control}> + <Dialog.Handle /> + + <LikesDialogInner {...props} /> + </Dialog.Outer> + ) +} + +export function LikesDialogInner({control, uri}: LikesDialogProps) { + const {_} = useLingui() + const t = useTheme() + + const { + data: resolvedUri, + error: resolveError, + isFetched: hasFetchedResolvedUri, + } = useResolveUriQuery(uri) + const { + data, + isFetching: isFetchingLikedBy, + isFetched: hasFetchedLikedBy, + isFetchingNextPage, + hasNextPage, + fetchNextPage, + isError, + error: likedByError, + } = useLikedByQuery(resolvedUri?.uri) + + const isLoading = !hasFetchedResolvedUri || !hasFetchedLikedBy + const likes = useMemo(() => { + if (data?.pages) { + return data.pages.flatMap(page => page.likes) + } + return [] + }, [data]) + + const onEndReached = useCallback(async () => { + if (isFetchingLikedBy || !hasNextPage || isError) return + try { + await fetchNextPage() + } catch (err) { + logger.error('Failed to load more likes', {message: err}) + } + }, [isFetchingLikedBy, hasNextPage, isError, fetchNextPage]) + + const renderItem = useCallback( + ({item}: {item: GetLikes.Like}) => { + return ( + <ProfileCardWithFollowBtn + key={item.actor.did} + profile={item.actor} + onPress={() => control.close()} + /> + ) + }, + [control], + ) + + return ( + <Dialog.Inner label={_(msg`Users that have liked this content or profile`)}> + <Text style={[a.text_2xl, a.font_bold, a.leading_tight, a.pb_lg]}> + <Trans>Liked by</Trans> + </Text> + + {isLoading ? ( + <View style={{minHeight: 300}}> + <Loader size="xl" /> + </View> + ) : resolveError || likedByError || !data ? ( + <ErrorMessage message={cleanError(resolveError || likedByError)} /> + ) : likes.length === 0 ? ( + <View style={[t.atoms.bg_contrast_50, a.px_md, a.py_xl, a.rounded_md]}> + <Text style={[a.text_center]}> + <Trans> + Nobody has liked this yet. Maybe you should be the first! + </Trans> + </Text> + </View> + ) : ( + <FlatList + data={likes} + keyExtractor={item => item.actor.did} + onEndReached={onEndReached} + renderItem={renderItem} + initialNumToRender={15} + ListFooterComponent={ + <ListFooterComponent isFetching={isFetchingNextPage} /> + } + /> + )} + + <Dialog.Close /> + </Dialog.Inner> + ) +} + +function ListFooterComponent({isFetching}: {isFetching: boolean}) { + if (isFetching) { + return ( + <View style={a.pt_lg}> + <ActivityIndicator /> + </View> + ) + } + return null +} diff --git a/src/components/Link.tsx b/src/components/Link.tsx index 8c963909b..7d0e83332 100644 --- a/src/components/Link.tsx +++ b/src/components/Link.tsx @@ -1,17 +1,13 @@ import React from 'react' import {GestureResponderEvent} from 'react-native' -import { - useLinkProps, - useNavigation, - StackActions, -} from '@react-navigation/native' +import {useLinkProps, StackActions} from '@react-navigation/native' import {sanitizeUrl} from '@braintree/sanitize-url' import {useInteractionState} from '#/components/hooks/useInteractionState' import {isWeb} from '#/platform/detection' import {useTheme, web, flatten, TextStyleProp, atoms as a} from '#/alf' import {Button, ButtonProps} from '#/components/Button' -import {AllNavigatorParams, NavigationProp} from '#/lib/routes/types' +import {AllNavigatorParams} from '#/lib/routes/types' import { convertBskyAppUrlIfNeeded, isExternalUrl, @@ -21,6 +17,7 @@ import {useModalControls} from '#/state/modals' import {router} from '#/routes' import {Text, TextProps} from '#/components/Typography' import {useOpenLink} from 'state/preferences/in-app-browser' +import {useNavigationDeduped} from 'lib/hooks/useNavigationDeduped' /** * Only available within a `Link`, since that inherits from `Button`. @@ -74,7 +71,7 @@ export function useLink({ }: BaseLinkProps & { displayText: string }) { - const navigation = useNavigation<NavigationProp>() + const navigation = useNavigationDeduped() const {href} = useLinkProps<AllNavigatorParams>({ to: typeof to === 'string' ? convertBskyAppUrlIfNeeded(sanitizeUrl(to)) : to, @@ -231,6 +228,7 @@ export function InlineLink({ onPress: outerOnPress, download, selectable, + label, ...rest }: InlineLinkProps) { const t = useTheme() @@ -253,12 +251,13 @@ export function InlineLink({ onIn: onPressIn, onOut: onPressOut, } = useInteractionState() - const flattenedStyle = flatten(style) + const flattenedStyle = flatten(style) || {} return ( <Text selectable={selectable} - label={href} + accessibilityHint="" + accessibilityLabel={label || href} {...rest} style={[ {color: t.palette.primary_500}, diff --git a/src/components/Lists.tsx b/src/components/Lists.tsx index 58aa74b38..d3e072028 100644 --- a/src/components/Lists.tsx +++ b/src/components/Lists.tsx @@ -1,27 +1,28 @@ import React from 'react' import {atoms as a, useBreakpoints, useTheme} from '#/alf' import {View} from 'react-native' +import {useLingui} from '@lingui/react' +import {Trans, msg} from '@lingui/macro' + import {CenteredView} from 'view/com/util/Views' import {Loader} from '#/components/Loader' -import {Trans} from '@lingui/macro' import {cleanError} from 'lib/strings/errors' import {Button} from '#/components/Button' import {Text} from '#/components/Typography' -import {StackActions} from '@react-navigation/native' -import {useNavigation} from '@react-navigation/core' -import {NavigationProp} from 'lib/routes/types' -import {router} from '#/routes' +import {Error} from '#/components/Error' export function ListFooter({ isFetching, isError, error, onRetry, + height, }: { - isFetching: boolean - isError: boolean + isFetching?: boolean + isError?: boolean error?: string onRetry?: () => Promise<unknown> + height?: number }) { const t = useTheme() @@ -30,11 +31,10 @@ export function ListFooter({ style={[ a.w_full, a.align_center, - a.justify_center, a.border_t, a.pb_lg, t.atoms.border_contrast_low, - {height: 100}, + {height: height ?? 180, paddingTop: 30}, ]}> {isFetching ? ( <Loader size="xl" /> @@ -54,11 +54,12 @@ function ListFooterMaybeError({ error, onRetry, }: { - isError: boolean + isError?: boolean error?: string onRetry?: () => Promise<unknown> }) { const t = useTheme() + const {_} = useLingui() if (!isError) return null @@ -84,7 +85,7 @@ function ListFooterMaybeError({ </Text> <Button variant="gradient" - label="Press to retry" + label={_(msg`Press to retry`)} style={[ a.align_center, a.justify_center, @@ -94,7 +95,7 @@ function ListFooterMaybeError({ a.py_sm, ]} onPress={onRetry}> - Retry + <Trans>Retry</Trans> </Button> </View> </View> @@ -129,121 +130,71 @@ export function ListMaybePlaceholder({ isLoading, isEmpty, isError, - empty, - error, - notFoundType = 'page', + emptyTitle, + emptyMessage, + errorTitle, + errorMessage, + emptyType = 'page', onRetry, }: { isLoading: boolean - isEmpty: boolean - isError: boolean - empty?: string - error?: string - notFoundType?: 'page' | 'results' + isEmpty?: boolean + isError?: boolean + emptyTitle?: string + emptyMessage?: string + errorTitle?: string + errorMessage?: string + emptyType?: 'page' | 'results' onRetry?: () => Promise<unknown> }) { - const navigation = useNavigation<NavigationProp>() const t = useTheme() + const {_} = useLingui() const {gtMobile, gtTablet} = useBreakpoints() - const canGoBack = navigation.canGoBack() - const onGoBack = React.useCallback(() => { - if (canGoBack) { - navigation.goBack() - } else { - navigation.navigate('HomeTab') - - // Checking the state for routes ensures that web doesn't encounter errors while going back - if (navigation.getState()?.routes) { - navigation.dispatch(StackActions.push(...router.matchPath('/'))) - } else { - navigation.navigate('HomeTab') - navigation.dispatch(StackActions.popToTop()) - } - } - }, [navigation, canGoBack]) + if (!isLoading && isError) { + return ( + <Error + title={errorTitle ?? _(msg`Oops!`)} + message={errorMessage ?? _(`Something went wrong!`)} + onRetry={onRetry} + /> + ) + } - if (!isEmpty) return null - - return ( - <CenteredView - style={[ - a.flex_1, - a.align_center, - !gtMobile ? a.justify_between : a.gap_5xl, - t.atoms.border_contrast_low, - {paddingTop: 175, paddingBottom: 110}, - ]} - sideBorders={gtMobile} - topBorder={!gtTablet}> - {isLoading ? ( + if (isLoading) { + return ( + <CenteredView + style={[ + a.flex_1, + a.align_center, + !gtMobile ? a.justify_between : a.gap_5xl, + t.atoms.border_contrast_low, + {paddingTop: 175, paddingBottom: 110}, + ]} + sideBorders={gtMobile} + topBorder={!gtTablet}> <View style={[a.w_full, a.align_center, {top: 100}]}> <Loader size="xl" /> </View> - ) : ( - <> - <View style={[a.w_full, a.align_center, a.gap_lg]}> - <Text style={[a.font_bold, a.text_3xl]}> - {isError ? ( - <Trans>Oops!</Trans> - ) : isEmpty ? ( - <> - {notFoundType === 'results' ? ( - <Trans>No results found</Trans> - ) : ( - <Trans>Page not found</Trans> - )} - </> - ) : undefined} - </Text> + </CenteredView> + ) + } - {isError ? ( - <Text - style={[a.text_md, a.text_center, t.atoms.text_contrast_high]}> - {error ? error : <Trans>Something went wrong!</Trans>} - </Text> - ) : isEmpty ? ( - <Text - style={[a.text_md, a.text_center, t.atoms.text_contrast_high]}> - {empty ? ( - empty - ) : ( - <Trans> - We're sorry! We can't find the page you were looking for. - </Trans> - )} - </Text> - ) : undefined} - </View> - <View - style={[a.gap_md, !gtMobile ? [a.w_full, a.px_lg] : {width: 350}]}> - {isError && onRetry && ( - <Button - variant="solid" - color="primary" - label="Click here" - onPress={onRetry} - size="large" - style={[ - a.rounded_sm, - a.overflow_hidden, - {paddingVertical: 10}, - ]}> - Retry - </Button> - )} - <Button - variant="solid" - color={isError && onRetry ? 'secondary' : 'primary'} - label="Click here" - onPress={onGoBack} - size="large" - style={[a.rounded_sm, a.overflow_hidden, {paddingVertical: 10}]}> - Go Back - </Button> - </View> - </> - )} - </CenteredView> - ) + if (isEmpty) { + return ( + <Error + title={ + emptyTitle ?? + (emptyType === 'results' + ? _(msg`No results found`) + : _(msg`Page not found`)) + } + message={ + emptyMessage ?? + _(msg`We're sorry! We can't find the page you were looking for.`) + } + onRetry={onRetry} + /> + ) + } } diff --git a/src/components/Menu/index.tsx b/src/components/Menu/index.tsx index ee96a5667..051e95b95 100644 --- a/src/components/Menu/index.tsx +++ b/src/components/Menu/index.tsx @@ -1,5 +1,5 @@ import React from 'react' -import {View, Pressable} from 'react-native' +import {View, Pressable, ViewStyle, StyleProp} from 'react-native' import flattenReactChildren from 'react-keyed-flatten-children' import {atoms as a, useTheme} from '#/alf' @@ -16,6 +16,10 @@ import { ItemTextProps, ItemIconProps, } from '#/components/Menu/types' +import {Button, ButtonText} from '#/components/Button' +import {Trans, msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {isNative} from 'platform/detection' export {useDialogControl as useMenuControl} from '#/components/Dialog' @@ -68,7 +72,13 @@ export function Trigger({children, label}: TriggerProps) { }) } -export function Outer({children}: React.PropsWithChildren<{}>) { +export function Outer({ + children, + showCancel, +}: React.PropsWithChildren<{ + showCancel?: boolean + style?: StyleProp<ViewStyle> +}>) { const context = React.useContext(Context) return ( @@ -78,7 +88,10 @@ export function Outer({children}: React.PropsWithChildren<{}>) { {/* Re-wrap with context since Dialogs are portal-ed to root */} <Context.Provider value={context}> <Dialog.ScrollableInner label="Menu TODO"> - <View style={[a.gap_lg]}>{children}</View> + <View style={[a.gap_lg]}> + {children} + {isNative && showCancel && <Cancel />} + </View> <View style={{height: a.gap_lg.gap}} /> </Dialog.ScrollableInner> </Context.Provider> @@ -185,6 +198,24 @@ export function Group({children, style}: GroupProps) { ) } +function Cancel() { + const {_} = useLingui() + const {control} = React.useContext(Context) + + return ( + <Button + label={_(msg`Close this dialog`)} + size="small" + variant="ghost" + color="secondary" + onPress={() => control.close()}> + <ButtonText> + <Trans>Cancel</Trans> + </ButtonText> + </Button> + ) +} + export function Divider() { return null } diff --git a/src/components/Menu/index.web.tsx b/src/components/Menu/index.web.tsx index 054e51b01..60b234203 100644 --- a/src/components/Menu/index.web.tsx +++ b/src/components/Menu/index.web.tsx @@ -1,6 +1,10 @@ +/* eslint-disable react/prop-types */ + import React from 'react' -import {View, Pressable} from 'react-native' +import {View, Pressable, ViewStyle, StyleProp} from 'react-native' import * as DropdownMenu from '@radix-ui/react-dropdown-menu' +import {msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' import * as Dialog from '#/components/Dialog' import {useInteractionState} from '#/components/hooks/useInteractionState' @@ -14,8 +18,10 @@ import { GroupProps, ItemTextProps, ItemIconProps, + RadixPassThroughTriggerProps, } from '#/components/Menu/types' import {Context} from '#/components/Menu/context' +import {Portal} from '#/components/Portal' export function useMenuControl(): Dialog.DialogControlProps { const id = React.useId() @@ -47,6 +53,7 @@ export function Root({ }: React.PropsWithChildren<{ control?: Dialog.DialogOuterProps['control'] }>) { + const {_} = useLingui() const defaultControl = useMenuControl() const context = React.useMemo<ContextType>( () => ({ @@ -67,6 +74,18 @@ export function Root({ return ( <Context.Provider value={context}> + {context.control.isOpen && ( + <Portal> + <Pressable + style={[a.fixed, a.inset_0, a.z_50]} + onPress={() => context.control.close()} + accessibilityHint="" + accessibilityLabel={_( + msg`Context menu backdrop, click to close the menu.`, + )} + /> + </Portal> + )} <DropdownMenu.Root open={context.control.isOpen} onOpenChange={onOpenChange}> @@ -76,7 +95,24 @@ export function Root({ ) } -export function Trigger({children, label, style}: TriggerProps) { +const RadixTriggerPassThrough = React.forwardRef( + ( + props: { + children: ( + props: RadixPassThroughTriggerProps & { + ref: React.Ref<any> + }, + ) => React.ReactNode + }, + ref, + ) => { + // @ts-expect-error Radix provides no types of this stuff + return props.children({...props, ref}) + }, +) +RadixTriggerPassThrough.displayName = 'RadixTriggerPassThrough' + +export function Trigger({children, label}: TriggerProps) { const {control} = React.useContext(Context) const { state: hovered, @@ -87,33 +123,42 @@ export function Trigger({children, label, style}: TriggerProps) { return ( <DropdownMenu.Trigger asChild> - <Pressable - accessibilityHint="" - accessibilityLabel={label} - onFocus={onFocus} - onBlur={onBlur} - style={flatten([style, focused && web({outline: 0})])} - onPointerDown={() => control.open()} - {...web({ - onMouseEnter, - onMouseLeave, - })}> - {children({ - isNative: false, - control, - state: { - hovered, - focused, - pressed: false, - }, - props: {}, - })} - </Pressable> + <RadixTriggerPassThrough> + {props => + children({ + isNative: false, + control, + state: { + hovered, + focused, + pressed: false, + }, + props: { + ...props, + // disable on web, use `onPress` + onPointerDown: () => false, + onPress: () => + control.isOpen ? control.close() : control.open(), + onFocus: onFocus, + onBlur: onBlur, + onMouseEnter, + onMouseLeave, + accessibilityLabel: label, + }, + }) + } + </RadixTriggerPassThrough> </DropdownMenu.Trigger> ) } -export function Outer({children}: React.PropsWithChildren<{}>) { +export function Outer({ + children, + style, +}: React.PropsWithChildren<{ + showCancel?: boolean + style?: StyleProp<ViewStyle> +}>) { const t = useTheme() return ( @@ -125,6 +170,7 @@ export function Outer({children}: React.PropsWithChildren<{}>) { a.p_xs, t.name === 'light' ? t.atoms.bg : t.atoms.bg_contrast_25, t.atoms.shadow_md, + style, ]}> {children} </View> @@ -177,7 +223,7 @@ export function Item({children, label, onPress, ...rest}: ItemProps) { style={flatten([ a.flex_row, a.align_center, - a.gap_sm, + a.gap_lg, a.py_sm, a.rounded_xs, {minHeight: 32, paddingHorizontal: 10}, diff --git a/src/components/Menu/types.ts b/src/components/Menu/types.ts index 2f52e6390..e710971ee 100644 --- a/src/components/Menu/types.ts +++ b/src/components/Menu/types.ts @@ -1,5 +1,9 @@ import React from 'react' -import {GestureResponderEvent, PressableProps} from 'react-native' +import { + GestureResponderEvent, + PressableProps, + AccessibilityProps, +} from 'react-native' import {Props as SVGIconProps} from '#/components/icons/common' import * as Dialog from '#/components/Dialog' @@ -9,7 +13,23 @@ export type ContextType = { control: Dialog.DialogOuterProps['control'] } -export type TriggerProps = ViewStyleProp & { +export type RadixPassThroughTriggerProps = { + id: string + type: 'button' + disabled: boolean + ['data-disabled']: boolean + ['data-state']: string + ['aria-controls']?: string + ['aria-haspopup']?: boolean + ['aria-expanded']?: AccessibilityProps['aria-expanded'] + onKeyDown: (e: React.KeyboardEvent) => void + /** + * Radix provides this, but we override on web to use `onPress` instead, + * which is less sensitive while scrolling. + */ + onPointerDown: PressableProps['onPointerDown'] +} +export type TriggerProps = { children(props: TriggerChildProps): React.ReactNode label: string } @@ -52,7 +72,14 @@ export type TriggerChildProps = */ pressed: false } - props: {} + props: RadixPassThroughTriggerProps & { + onPress: () => void + onFocus: () => void + onBlur: () => void + onMouseEnter: () => void + onMouseLeave: () => void + accessibilityLabel: string + } } export type ItemProps = React.PropsWithChildren< diff --git a/src/components/Prompt.tsx b/src/components/Prompt.tsx index 3b245c440..b81b20707 100644 --- a/src/components/Prompt.tsx +++ b/src/components/Prompt.tsx @@ -1,11 +1,11 @@ import React from 'react' -import {View, PressableProps} from 'react-native' +import {View} from 'react-native' import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' import {useTheme, atoms as a, useBreakpoints} from '#/alf' import {Text} from '#/components/Typography' -import {Button} from '#/components/Button' +import {Button, ButtonColor, ButtonText} from '#/components/Button' import * as Dialog from '#/components/Dialog' @@ -22,8 +22,10 @@ const Context = React.createContext<{ export function Outer({ children, control, + testID, }: React.PropsWithChildren<{ control: Dialog.DialogOuterProps['control'] + testID?: string }>) { const {gtMobile} = useBreakpoints() const titleId = React.useId() @@ -35,7 +37,7 @@ export function Outer({ ) return ( - <Dialog.Outer control={control}> + <Dialog.Outer control={control} testID={testID}> <Context.Provider value={context}> <Dialog.Handle /> @@ -80,7 +82,9 @@ export function Actions({children}: React.PropsWithChildren<{}>) { a.w_full, a.gap_sm, a.justify_end, - gtMobile ? [a.flex_row] : [a.flex_col, a.pt_md, a.pb_4xl], + gtMobile + ? [a.flex_row, a.flex_row_reverse, a.justify_start] + : [a.flex_col], ]}> {children} </View> @@ -89,18 +93,29 @@ export function Actions({children}: React.PropsWithChildren<{}>) { export function Cancel({ children, -}: React.PropsWithChildren<{onPress?: PressableProps['onPress']}>) { + cta, +}: React.PropsWithChildren<{ + /** + * Optional i18n string, used in lieu of `children` for simple buttons. If + * undefined (and `children` is undefined), it will default to "Cancel". + */ + cta?: string +}>) { const {_} = useLingui() const {gtMobile} = useBreakpoints() const {close} = Dialog.useDialogContext() + const onPress = React.useCallback(() => { + close() + }, [close]) + return ( <Button variant="solid" color="secondary" size={gtMobile ? 'small' : 'medium'} - label={_(msg`Cancel`)} - onPress={() => close()}> - {children} + label={cta || _(msg`Cancel`)} + onPress={onPress}> + {children ? children : <ButtonText>{cta || _(msg`Cancel`)}</ButtonText>} </Button> ) } @@ -108,22 +123,70 @@ export function Cancel({ export function Action({ children, onPress, -}: React.PropsWithChildren<{onPress?: () => void}>) { + color = 'primary', + cta, + testID, +}: React.PropsWithChildren<{ + onPress: () => void + color?: ButtonColor + /** + * Optional i18n string, used in lieu of `children` for simple buttons. If + * undefined (and `children` is undefined), it will default to "Confirm". + */ + cta?: string + testID?: string +}>) { const {_} = useLingui() const {gtMobile} = useBreakpoints() const {close} = Dialog.useDialogContext() const handleOnPress = React.useCallback(() => { close() - onPress?.() + onPress() }, [close, onPress]) + return ( <Button variant="solid" - color="primary" + color={color} size={gtMobile ? 'small' : 'medium'} - label={_(msg`Confirm`)} - onPress={handleOnPress}> - {children} + label={cta || _(msg`Confirm`)} + onPress={handleOnPress} + testID={testID}> + {children ? children : <ButtonText>{cta || _(msg`Confirm`)}</ButtonText>} </Button> ) } + +export function Basic({ + control, + title, + description, + cancelButtonCta, + confirmButtonCta, + onConfirm, + confirmButtonColor, +}: React.PropsWithChildren<{ + control: Dialog.DialogOuterProps['control'] + title: string + description: string + cancelButtonCta?: string + confirmButtonCta?: string + onConfirm: () => void + confirmButtonColor?: ButtonColor +}>) { + return ( + <Outer control={control} testID="confirmModal"> + <Title>{title}</Title> + <Description>{description}</Description> + <Actions> + <Action + cta={confirmButtonCta} + onPress={onConfirm} + color={confirmButtonColor} + testID="confirmBtn" + /> + <Cancel cta={cancelButtonCta} /> + </Actions> + </Outer> + ) +} diff --git a/src/components/ReportDialog/SelectLabelerView.tsx b/src/components/ReportDialog/SelectLabelerView.tsx new file mode 100644 index 000000000..817426355 --- /dev/null +++ b/src/components/ReportDialog/SelectLabelerView.tsx @@ -0,0 +1,92 @@ +import React from 'react' +import {View} from 'react-native' +import {msg, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {AppBskyLabelerDefs} from '@atproto/api' + +export {useDialogControl as useReportDialogControl} from '#/components/Dialog' +import {getLabelingServiceTitle} from '#/lib/moderation' + +import {atoms as a, useTheme, useBreakpoints} from '#/alf' +import {Text} from '#/components/Typography' +import {Button, useButtonContext} from '#/components/Button' +import {Divider} from '#/components/Divider' +import * as LabelingServiceCard from '#/components/LabelingServiceCard' + +import {ReportDialogProps} from './types' + +export function SelectLabelerView({ + ...props +}: ReportDialogProps & { + labelers: AppBskyLabelerDefs.LabelerViewDetailed[] + onSelectLabeler: (v: string) => void +}) { + const t = useTheme() + const {_} = useLingui() + const {gtMobile} = useBreakpoints() + + return ( + <View style={[a.gap_lg]}> + <View style={[a.justify_center, gtMobile ? a.gap_sm : a.gap_xs]}> + <Text style={[a.text_2xl, a.font_bold]}> + <Trans>Select moderator</Trans> + </Text> + <Text style={[a.text_md, t.atoms.text_contrast_medium]}> + <Trans>To whom would you like to send this report?</Trans> + </Text> + </View> + + <Divider /> + + <View style={[a.gap_xs, {marginHorizontal: a.p_md.padding * -1}]}> + {props.labelers.map(labeler => { + return ( + <Button + key={labeler.creator.did} + label={_(msg`Send report to ${labeler.creator.displayName}`)} + onPress={() => props.onSelectLabeler(labeler.creator.did)}> + <LabelerButton labeler={labeler} /> + </Button> + ) + })} + </View> + </View> + ) +} + +function LabelerButton({ + labeler, +}: { + labeler: AppBskyLabelerDefs.LabelerViewDetailed +}) { + const t = useTheme() + const {hovered, pressed} = useButtonContext() + const interacted = hovered || pressed + + const styles = React.useMemo(() => { + return { + interacted: { + backgroundColor: t.palette.contrast_50, + }, + } + }, [t]) + + return ( + <LabelingServiceCard.Outer + style={[a.p_md, a.rounded_sm, interacted && styles.interacted]}> + <LabelingServiceCard.Avatar avatar={labeler.creator.avatar} /> + <LabelingServiceCard.Content> + <LabelingServiceCard.Title + value={getLabelingServiceTitle({ + displayName: labeler.creator.displayName, + handle: labeler.creator.handle, + })} + /> + <Text + style={[t.atoms.text_contrast_medium, a.text_sm, a.font_semibold]}> + @{labeler.creator.handle} + </Text> + </LabelingServiceCard.Content> + </LabelingServiceCard.Outer> + ) +} diff --git a/src/components/ReportDialog/SelectReportOptionView.tsx b/src/components/ReportDialog/SelectReportOptionView.tsx new file mode 100644 index 000000000..bacf5a867 --- /dev/null +++ b/src/components/ReportDialog/SelectReportOptionView.tsx @@ -0,0 +1,200 @@ +import React from 'react' +import {View} from 'react-native' +import {msg, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {AppBskyLabelerDefs} from '@atproto/api' + +import {useReportOptions, ReportOption} from '#/lib/moderation/useReportOptions' +import {DMCA_LINK} from '#/components/ReportDialog/const' +import {Link} from '#/components/Link' +export {useDialogControl as useReportDialogControl} from '#/components/Dialog' + +import {atoms as a, useTheme, useBreakpoints} from '#/alf' +import {Text} from '#/components/Typography' +import { + Button, + ButtonIcon, + ButtonText, + useButtonContext, +} from '#/components/Button' +import {Divider} from '#/components/Divider' +import { + ChevronRight_Stroke2_Corner0_Rounded as ChevronRight, + ChevronLeft_Stroke2_Corner0_Rounded as ChevronLeft, +} from '#/components/icons/Chevron' +import {SquareArrowTopRight_Stroke2_Corner0_Rounded as SquareArrowTopRight} from '#/components/icons/SquareArrowTopRight' + +import {ReportDialogProps} from './types' + +export function SelectReportOptionView({ + ...props +}: ReportDialogProps & { + labelers: AppBskyLabelerDefs.LabelerViewDetailed[] + onSelectReportOption: (reportOption: ReportOption) => void + goBack: () => void +}) { + const t = useTheme() + const {_} = useLingui() + const {gtMobile} = useBreakpoints() + const allReportOptions = useReportOptions() + const reportOptions = allReportOptions[props.params.type] + + const i18n = React.useMemo(() => { + let title = _(msg`Report this content`) + let description = _(msg`Why should this content be reviewed?`) + + if (props.params.type === 'account') { + title = _(msg`Report this user`) + description = _(msg`Why should this user be reviewed?`) + } else if (props.params.type === 'post') { + title = _(msg`Report this post`) + description = _(msg`Why should this post be reviewed?`) + } else if (props.params.type === 'list') { + title = _(msg`Report this list`) + description = _(msg`Why should this list be reviewed?`) + } else if (props.params.type === 'feedgen') { + title = _(msg`Report this feed`) + description = _(msg`Why should this feed be reviewed?`) + } + + return { + title, + description, + } + }, [_, props.params.type]) + + return ( + <View style={[a.gap_lg]}> + {props.labelers?.length > 1 ? ( + <Button + size="small" + variant="solid" + color="secondary" + shape="round" + label={_(msg`Go back to previous step`)} + onPress={props.goBack}> + <ButtonIcon icon={ChevronLeft} /> + </Button> + ) : null} + + <View style={[a.justify_center, gtMobile ? a.gap_sm : a.gap_xs]}> + <Text style={[a.text_2xl, a.font_bold]}>{i18n.title}</Text> + <Text style={[a.text_md, t.atoms.text_contrast_medium]}> + {i18n.description} + </Text> + </View> + + <Divider /> + + <View style={[a.gap_sm, {marginHorizontal: a.p_md.padding * -1}]}> + {reportOptions.map(reportOption => { + return ( + <Button + key={reportOption.reason} + label={_(msg`Create report for ${reportOption.title}`)} + onPress={() => props.onSelectReportOption(reportOption)}> + <ReportOptionButton + title={reportOption.title} + description={reportOption.description} + /> + </Button> + ) + })} + + {(props.params.type === 'post' || props.params.type === 'account') && ( + <View style={[a.pt_md, a.px_md]}> + <View + style={[ + a.flex_row, + a.align_center, + a.justify_between, + a.gap_lg, + a.p_md, + a.pl_lg, + a.rounded_md, + t.atoms.bg_contrast_900, + ]}> + <Text + style={[ + a.flex_1, + t.atoms.text_inverted, + a.italic, + a.leading_snug, + ]}> + <Trans>Need to report a copyright violation?</Trans> + </Text> + <Link + to={DMCA_LINK} + label={_(msg`View details for reporting a copyright violation`)} + size="small" + variant="solid" + color="secondary"> + <ButtonText> + <Trans>View details</Trans> + </ButtonText> + <ButtonIcon position="right" icon={SquareArrowTopRight} /> + </Link> + </View> + </View> + )} + </View> + </View> + ) +} + +function ReportOptionButton({ + title, + description, +}: { + title: string + description: string +}) { + const t = useTheme() + const {hovered, pressed} = useButtonContext() + const interacted = hovered || pressed + + const styles = React.useMemo(() => { + return { + interacted: { + backgroundColor: t.palette.contrast_50, + }, + } + }, [t]) + + return ( + <View + style={[ + a.w_full, + a.flex_row, + a.align_center, + a.justify_between, + a.p_md, + a.rounded_md, + {paddingRight: 70}, + interacted && styles.interacted, + ]}> + <View style={[a.flex_1, a.gap_xs]}> + <Text style={[a.text_md, a.font_bold, t.atoms.text_contrast_medium]}> + {title} + </Text> + <Text style={[a.leading_tight, {maxWidth: 400}]}>{description}</Text> + </View> + + <View + style={[ + a.absolute, + a.inset_0, + a.justify_center, + a.pr_md, + {left: 'auto'}, + ]}> + <ChevronRight + size="md" + fill={ + hovered ? t.palette.primary_500 : t.atoms.text_contrast_low.color + } + /> + </View> + </View> + ) +} diff --git a/src/components/ReportDialog/SubmitView.tsx b/src/components/ReportDialog/SubmitView.tsx new file mode 100644 index 000000000..d47211c81 --- /dev/null +++ b/src/components/ReportDialog/SubmitView.tsx @@ -0,0 +1,264 @@ +import React from 'react' +import {View} from 'react-native' +import {msg, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {AppBskyLabelerDefs} from '@atproto/api' + +import {getLabelingServiceTitle} from '#/lib/moderation' +import {ReportOption} from '#/lib/moderation/useReportOptions' + +import {atoms as a, useTheme, native} from '#/alf' +import {Text} from '#/components/Typography' +import * as Dialog from '#/components/Dialog' +import {Button, ButtonIcon, ButtonText} from '#/components/Button' +import {ChevronLeft_Stroke2_Corner0_Rounded as ChevronLeft} from '#/components/icons/Chevron' +import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check' +import * as Toggle from '#/components/forms/Toggle' +import {CharProgress} from '#/view/com/composer/char-progress/CharProgress' +import {Loader} from '#/components/Loader' +import * as Toast from '#/view/com/util/Toast' + +import {ReportDialogProps} from './types' +import {getAgent} from '#/state/session' + +export function SubmitView({ + params, + labelers, + selectedLabeler, + selectedReportOption, + goBack, + onSubmitComplete, +}: ReportDialogProps & { + labelers: AppBskyLabelerDefs.LabelerViewDetailed[] + selectedLabeler: string + selectedReportOption: ReportOption + goBack: () => void + onSubmitComplete: () => void +}) { + const t = useTheme() + const {_} = useLingui() + const [details, setDetails] = React.useState<string>('') + const [submitting, setSubmitting] = React.useState<boolean>(false) + const [selectedServices, setSelectedServices] = React.useState<string[]>([ + selectedLabeler, + ]) + const [error, setError] = React.useState('') + + const submit = React.useCallback(async () => { + setSubmitting(true) + setError('') + + const $type = + params.type === 'account' + ? 'com.atproto.admin.defs#repoRef' + : 'com.atproto.repo.strongRef' + const report = { + reasonType: selectedReportOption.reason, + subject: { + $type, + ...params, + }, + reason: details, + } + const results = await Promise.all( + selectedServices.map(did => + getAgent() + .withProxy('atproto_labeler', did) + .createModerationReport(report) + .then( + _ => true, + _ => false, + ), + ), + ) + + setSubmitting(false) + + if (results.includes(true)) { + Toast.show(_(msg`Thank you. Your report has been sent.`)) + onSubmitComplete() + } else { + setError( + _( + msg`There was an issue sending your report. Please check your internet connection.`, + ), + ) + } + }, [ + _, + params, + details, + selectedReportOption, + selectedServices, + onSubmitComplete, + setError, + ]) + + return ( + <View style={[a.gap_2xl]}> + <Button + size="small" + variant="solid" + color="secondary" + shape="round" + label={_(msg`Go back to previous step`)} + onPress={goBack}> + <ButtonIcon icon={ChevronLeft} /> + </Button> + + <View + style={[ + a.w_full, + a.flex_row, + a.align_center, + a.justify_between, + a.gap_lg, + a.p_md, + a.rounded_md, + a.border, + t.atoms.border_contrast_low, + ]}> + <View style={[a.flex_1, a.gap_xs]}> + <Text style={[a.text_md, a.font_bold]}> + {selectedReportOption.title} + </Text> + <Text style={[a.leading_tight, {maxWidth: 400}]}> + {selectedReportOption.description} + </Text> + </View> + + <Check size="md" style={[a.pr_sm, t.atoms.text_contrast_low]} /> + </View> + + <View style={[a.gap_md]}> + <Text style={[t.atoms.text_contrast_medium]}> + <Trans>Select the moderation service(s) to report to</Trans> + </Text> + + <Toggle.Group + label="Select mod services" + values={selectedServices} + onChange={setSelectedServices}> + <View style={[a.flex_row, a.gap_md, a.flex_wrap]}> + {labelers.map(labeler => { + const title = getLabelingServiceTitle({ + displayName: labeler.creator.displayName, + handle: labeler.creator.handle, + }) + return ( + <Toggle.Item + key={labeler.creator.did} + name={labeler.creator.did} + label={title}> + <LabelerToggle title={title} /> + </Toggle.Item> + ) + })} + </View> + </Toggle.Group> + </View> + <View style={[a.gap_md]}> + <Text style={[t.atoms.text_contrast_medium]}> + <Trans>Optionally provide additional information below:</Trans> + </Text> + + <View style={[a.relative, a.w_full]}> + <Dialog.Input + multiline + value={details} + onChangeText={setDetails} + label="Text field" + style={{paddingRight: 60}} + numberOfLines={6} + /> + + <View + style={[ + a.absolute, + a.flex_row, + a.align_center, + a.pr_md, + a.pb_sm, + { + bottom: 0, + right: 0, + }, + ]}> + <CharProgress count={details?.length || 0} /> + </View> + </View> + </View> + + <View style={[a.flex_row, a.align_center, a.justify_end, a.gap_lg]}> + {!selectedServices.length || + (error && ( + <Text + style={[ + a.flex_1, + a.italic, + a.leading_snug, + t.atoms.text_contrast_medium, + ]}> + {error ? ( + error + ) : ( + <Trans>You must select at least one labeler for a report</Trans> + )} + </Text> + ))} + + <Button + size="large" + variant="solid" + color="negative" + label={_(msg`Send report`)} + onPress={submit} + disabled={!selectedServices.length}> + <ButtonText> + <Trans>Send report</Trans> + </ButtonText> + {submitting && <ButtonIcon icon={Loader} />} + </Button> + </View> + </View> + ) +} + +function LabelerToggle({title}: {title: string}) { + const t = useTheme() + const ctx = Toggle.useItemContext() + + return ( + <View + style={[ + a.flex_row, + a.align_center, + a.gap_md, + a.p_md, + a.pr_lg, + a.rounded_sm, + a.overflow_hidden, + t.atoms.bg_contrast_25, + ctx.selected && [t.atoms.bg_contrast_50], + ]}> + <Toggle.Checkbox /> + <View + style={[ + a.flex_row, + a.align_center, + a.justify_between, + a.gap_lg, + a.z_10, + ]}> + <Text + style={[ + native({marginTop: 2}), + t.atoms.text_contrast_medium, + ctx.selected && t.atoms.text, + ]}> + {title} + </Text> + </View> + </View> + ) +} diff --git a/src/components/ReportDialog/const.ts b/src/components/ReportDialog/const.ts new file mode 100644 index 000000000..30c9aff88 --- /dev/null +++ b/src/components/ReportDialog/const.ts @@ -0,0 +1 @@ +export const DMCA_LINK = 'https://bsky.social/about/support/copyright' diff --git a/src/components/ReportDialog/index.tsx b/src/components/ReportDialog/index.tsx new file mode 100644 index 000000000..f01ff3f3b --- /dev/null +++ b/src/components/ReportDialog/index.tsx @@ -0,0 +1,95 @@ +import React from 'react' +import {View, Pressable} from 'react-native' +import {Trans} from '@lingui/macro' + +import {useMyLabelersQuery} from '#/state/queries/preferences' +import {ReportOption} from '#/lib/moderation/useReportOptions' +export {useDialogControl as useReportDialogControl} from '#/components/Dialog' + +import {atoms as a} from '#/alf' +import {Loader} from '#/components/Loader' +import * as Dialog from '#/components/Dialog' +import {Text} from '#/components/Typography' + +import {ReportDialogProps} from './types' +import {SelectLabelerView} from './SelectLabelerView' +import {SelectReportOptionView} from './SelectReportOptionView' +import {SubmitView} from './SubmitView' +import {useDelayedLoading} from '#/components/hooks/useDelayedLoading' +import {AppBskyLabelerDefs} from '@atproto/api' + +export function ReportDialog(props: ReportDialogProps) { + return ( + <Dialog.Outer control={props.control}> + <Dialog.Handle /> + + <ReportDialogInner {...props} /> + </Dialog.Outer> + ) +} + +function ReportDialogInner(props: ReportDialogProps) { + const { + isLoading: isLabelerLoading, + data: labelers, + error, + } = useMyLabelersQuery() + const isLoading = useDelayedLoading(500, isLabelerLoading) + + return ( + <Dialog.ScrollableInner label="Report Dialog"> + {isLoading ? ( + <View style={[a.align_center, {height: 100}]}> + <Loader size="xl" /> + {/* Here to capture focus for a hot sec to prevent flash */} + <Pressable accessible={false} /> + </View> + ) : error || !labelers ? ( + <View> + <Text style={[a.text_md]}> + <Trans>Something went wrong, please try again.</Trans> + </Text> + </View> + ) : ( + <ReportDialogLoaded labelers={labelers} {...props} /> + )} + + <Dialog.Close /> + </Dialog.ScrollableInner> + ) +} + +function ReportDialogLoaded( + props: ReportDialogProps & { + labelers: AppBskyLabelerDefs.LabelerViewDetailed[] + }, +) { + const [selectedLabeler, setSelectedLabeler] = React.useState< + string | undefined + >(props.labelers.length === 1 ? props.labelers[0].creator.did : undefined) + const [selectedReportOption, setSelectedReportOption] = React.useState< + ReportOption | undefined + >() + + if (selectedReportOption && selectedLabeler) { + return ( + <SubmitView + {...props} + selectedLabeler={selectedLabeler} + selectedReportOption={selectedReportOption} + goBack={() => setSelectedReportOption(undefined)} + onSubmitComplete={() => props.control.close()} + /> + ) + } + if (selectedLabeler) { + return ( + <SelectReportOptionView + {...props} + goBack={() => setSelectedLabeler(undefined)} + onSelectReportOption={setSelectedReportOption} + /> + ) + } + return <SelectLabelerView {...props} onSelectLabeler={setSelectedLabeler} /> +} diff --git a/src/components/ReportDialog/types.ts b/src/components/ReportDialog/types.ts new file mode 100644 index 000000000..0c8a1e077 --- /dev/null +++ b/src/components/ReportDialog/types.ts @@ -0,0 +1,15 @@ +import * as Dialog from '#/components/Dialog' + +export type ReportDialogProps = { + control: Dialog.DialogOuterProps['control'] + params: + | { + type: 'post' | 'list' | 'feedgen' | 'other' + uri: string + cid: string + } + | { + type: 'account' + did: string + } +} diff --git a/src/components/TagMenu/index.tsx b/src/components/TagMenu/index.tsx index 849a3f42d..0ed703667 100644 --- a/src/components/TagMenu/index.tsx +++ b/src/components/TagMenu/index.tsx @@ -59,7 +59,7 @@ export function TagMenu({ const displayTag = '#' + tag const isMuted = Boolean( - (preferences?.mutedWords?.find( + (preferences?.moderationPrefs.mutedWords?.find( m => m.value === tag && m.targets.includes('tag'), ) ?? optimisticUpsert?.find( @@ -264,7 +264,9 @@ export function TagMenu({ variant="ghost" color="secondary" onPress={() => control.close()}> - <ButtonText>Cancel</ButtonText> + <ButtonText> + <Trans>Cancel</Trans> + </ButtonText> </Button> </> )} diff --git a/src/components/TagMenu/index.web.tsx b/src/components/TagMenu/index.web.tsx index 8245bd019..b2f5c9075 100644 --- a/src/components/TagMenu/index.web.tsx +++ b/src/components/TagMenu/index.web.tsx @@ -50,7 +50,7 @@ export function TagMenu({ const {mutateAsync: removeMutedWord, variables: optimisticRemove} = useRemoveMutedWordMutation() const isMuted = Boolean( - (preferences?.mutedWords?.find( + (preferences?.moderationPrefs.mutedWords?.find( m => m.value === tag && m.targets.includes('tag'), ) ?? optimisticUpsert?.find( diff --git a/src/components/Typography.tsx b/src/components/Typography.tsx index c9ab7a8a1..f8b3ad1bd 100644 --- a/src/components/Typography.tsx +++ b/src/components/Typography.tsx @@ -1,9 +1,14 @@ import React from 'react' -import {Text as RNText, TextStyle, TextProps as RNTextProps} from 'react-native' +import { + Text as RNText, + StyleProp, + TextStyle, + TextProps as RNTextProps, +} from 'react-native' import {UITextView} from 'react-native-ui-text-view' import {useTheme, atoms, web, flatten} from '#/alf' -import {isIOS} from '#/platform/detection' +import {isIOS, isNative} from '#/platform/detection' export type TextProps = RNTextProps & { /** @@ -34,17 +39,17 @@ export function leading< * If the `lineHeight` value is > 2, we assume it's an absolute value and * returns it as-is. */ -function normalizeTextStyles(styles: TextStyle[]) { +export function normalizeTextStyles(styles: StyleProp<TextStyle>) { const s = flatten(styles) // should always be defined on these components const fontSize = s.fontSize || atoms.text_md.fontSize if (s?.lineHeight) { - if (s.lineHeight <= 2) { + if (s.lineHeight !== 0 && s.lineHeight <= 2) { s.lineHeight = Math.round(fontSize * s.lineHeight) } - } else { - s.lineHeight = fontSize + } else if (!isNative) { + s.lineHeight = s.fontSize } return s diff --git a/src/components/dialogs/BirthDateSettings.tsx b/src/components/dialogs/BirthDateSettings.tsx new file mode 100644 index 000000000..4a3e96e56 --- /dev/null +++ b/src/components/dialogs/BirthDateSettings.tsx @@ -0,0 +1,132 @@ +import React from 'react' +import {useLingui} from '@lingui/react' +import {Trans, msg} from '@lingui/macro' +import {View} from 'react-native' + +import * as Dialog from '#/components/Dialog' +import {Text} from '../Typography' +import {DateInput} from '#/view/com/util/forms/DateInput' +import {logger} from '#/logger' +import { + usePreferencesQuery, + usePreferencesSetBirthDateMutation, + UsePreferencesQueryResponse, +} from '#/state/queries/preferences' +import {Button, ButtonIcon, ButtonText} from '../Button' +import {atoms as a, useTheme} from '#/alf' +import {ErrorMessage} from '#/view/com/util/error/ErrorMessage' +import {cleanError} from '#/lib/strings/errors' +import {isIOS, isWeb} from '#/platform/detection' +import {Loader} from '#/components/Loader' + +export function BirthDateSettingsDialog({ + control, +}: { + control: Dialog.DialogControlProps +}) { + const t = useTheme() + const {_} = useLingui() + const {isLoading, error, data: preferences} = usePreferencesQuery() + + return ( + <Dialog.Outer control={control}> + <Dialog.Handle /> + + <Dialog.ScrollableInner label={_(msg`My Birthday`)}> + <View style={[a.gap_sm, a.pb_lg]}> + <Text style={[a.text_2xl, a.font_bold]}> + <Trans>My Birthday</Trans> + </Text> + <Text style={[a.text_md, t.atoms.text_contrast_medium]}> + <Trans>This information is not shared with other users.</Trans> + </Text> + </View> + + {isLoading ? ( + <Loader size="xl" /> + ) : error || !preferences ? ( + <ErrorMessage + message={ + error?.toString() || + _( + msg`We were unable to load your birth date preferences. Please try again.`, + ) + } + style={[a.rounded_sm]} + /> + ) : ( + <BirthdayInner control={control} preferences={preferences} /> + )} + + <Dialog.Close /> + </Dialog.ScrollableInner> + </Dialog.Outer> + ) +} + +function BirthdayInner({ + control, + preferences, +}: { + control: Dialog.DialogControlProps + preferences: UsePreferencesQueryResponse +}) { + const {_} = useLingui() + const [date, setDate] = React.useState(preferences.birthDate || new Date()) + const { + isPending, + isError, + error, + mutateAsync: setBirthDate, + } = usePreferencesSetBirthDateMutation() + const hasChanged = date !== preferences.birthDate + + const onSave = React.useCallback(async () => { + try { + // skip if date is the same + if (hasChanged) { + await setBirthDate({birthDate: date}) + } + control.close() + } catch (e: any) { + logger.error(`setBirthDate failed`, {message: e.message}) + } + }, [date, setBirthDate, control, hasChanged]) + + return ( + <View style={a.gap_lg} testID="birthDateSettingsDialog"> + <View style={isIOS && [a.w_full, a.align_center]}> + <DateInput + handleAsUTC + testID="birthdayInput" + value={date} + onChange={setDate} + buttonType="default-light" + buttonStyle={[a.rounded_sm]} + buttonLabelType="lg" + accessibilityLabel={_(msg`Birthday`)} + accessibilityHint={_(msg`Enter your birth date`)} + accessibilityLabelledBy="birthDate" + /> + </View> + + {isError ? ( + <ErrorMessage message={cleanError(error)} style={[a.rounded_sm]} /> + ) : undefined} + + <View style={isWeb && [a.flex_row, a.justify_end]}> + <Button + label={hasChanged ? _(msg`Save birthday`) : _(msg`Done`)} + size="medium" + onPress={onSave} + variant="solid" + color="primary"> + <ButtonText> + {hasChanged ? <Trans>Save</Trans> : <Trans>Done</Trans>} + </ButtonText> + {isPending && <ButtonIcon icon={Loader} />} + </Button> + </View> + </View> + ) +} diff --git a/src/components/dialogs/Context.tsx b/src/components/dialogs/Context.tsx index d86c90a92..87bd5c2ed 100644 --- a/src/components/dialogs/Context.tsx +++ b/src/components/dialogs/Context.tsx @@ -18,7 +18,7 @@ export function useGlobalDialogsControlContext() { export function Provider({children}: React.PropsWithChildren<{}>) { const mutedWordsDialogControl = Dialog.useDialogControl() - const ctx = React.useMemo( + const ctx = React.useMemo<ControlsContext>( () => ({mutedWordsDialogControl}), [mutedWordsDialogControl], ) diff --git a/src/components/dialogs/MutedWords.tsx b/src/components/dialogs/MutedWords.tsx index 658ba2aae..46f319adf 100644 --- a/src/components/dialogs/MutedWords.tsx +++ b/src/components/dialogs/MutedWords.tsx @@ -233,8 +233,8 @@ function MutedWordsInner({}: {control: Dialog.DialogOuterProps['control']}) { </Trans> </Text> </View> - ) : preferences.mutedWords.length ? ( - [...preferences.mutedWords] + ) : preferences.moderationPrefs.mutedWords.length ? ( + [...preferences.moderationPrefs.mutedWords] .reverse() .map((word, i) => ( <MutedWordRow @@ -254,9 +254,9 @@ function MutedWordsInner({}: {control: Dialog.DialogOuterProps['control']}) { </View> {isNative && <View style={{height: 20}} />} - - <Dialog.Close /> </View> + + <Dialog.Close /> </Dialog.ScrollableInner> ) } @@ -277,29 +277,16 @@ function MutedWordRow({ return ( <> - <Prompt.Outer control={control}> - <Prompt.Title> - <Trans>Are you sure?</Trans> - </Prompt.Title> - <Prompt.Description> - <Trans> - This will delete {word.value} from your muted words. You can always - add it back later. - </Trans> - </Prompt.Description> - <Prompt.Actions> - <Prompt.Cancel> - <ButtonText> - <Trans>Nevermind</Trans> - </ButtonText> - </Prompt.Cancel> - <Prompt.Action onPress={remove}> - <ButtonText> - <Trans>Remove</Trans> - </ButtonText> - </Prompt.Action> - </Prompt.Actions> - </Prompt.Outer> + <Prompt.Basic + control={control} + title={_(msg`Are you sure?`)} + description={_( + msg`This will delete ${word.value} from your muted words. You can always add it back later.`, + )} + onConfirm={remove} + confirmButtonCta={_(msg`Remove`)} + confirmButtonColor="negative" + /> <View style={[ diff --git a/src/components/forms/Toggle.tsx b/src/components/forms/Toggle.tsx index a83f92a2a..7a4b5ac95 100644 --- a/src/components/forms/Toggle.tsx +++ b/src/components/forms/Toggle.tsx @@ -2,7 +2,14 @@ import React from 'react' import {Pressable, View, ViewStyle} from 'react-native' import {HITSLOP_10} from 'lib/constants' -import {useTheme, atoms as a, web, native, flatten, ViewStyleProp} from '#/alf' +import { + useTheme, + atoms as a, + native, + flatten, + ViewStyleProp, + TextStyleProp, +} from '#/alf' import {Text} from '#/components/Typography' import {useInteractionState} from '#/components/hooks/useInteractionState' import {CheckThick_Stroke2_Corner0_Rounded as Checkmark} from '#/components/icons/Check' @@ -220,20 +227,17 @@ export function Item({ onPressOut={onPressOut} onFocus={onFocus} onBlur={onBlur} - style={[ - a.flex_row, - a.align_center, - a.gap_sm, - focused ? web({outline: 'none'}) : {}, - flatten(style), - ]}> + style={[a.flex_row, a.align_center, a.gap_sm, flatten(style)]}> {typeof children === 'function' ? children(state) : children} </Pressable> </ItemContext.Provider> ) } -export function Label({children}: React.PropsWithChildren<{}>) { +export function Label({ + children, + style, +}: React.PropsWithChildren<TextStyleProp>) { const t = useTheme() const {disabled} = useItemContext() return ( @@ -242,11 +246,14 @@ export function Label({children}: React.PropsWithChildren<{}>) { a.font_bold, { userSelect: 'none', - color: disabled ? t.palette.contrast_400 : t.palette.contrast_600, + color: disabled + ? t.atoms.text_contrast_low.color + : t.atoms.text_contrast_high.color, }, native({ paddingTop: 3, }), + flatten(style), ]}> {children} </Text> @@ -257,7 +264,6 @@ export function Label({children}: React.PropsWithChildren<{}>) { export function createSharedToggleStyles({ theme: t, hovered, - focused, selected, disabled, isInvalid, @@ -280,7 +286,7 @@ export function createSharedToggleStyles({ borderColor: t.palette.primary_500, }) - if (hovered || focused) { + if (hovered) { baseHover.push({ backgroundColor: t.name === 'light' ? t.palette.primary_100 : t.palette.primary_800, @@ -289,7 +295,7 @@ export function createSharedToggleStyles({ }) } } else { - if (hovered || focused) { + if (hovered) { baseHover.push({ backgroundColor: t.name === 'light' ? t.palette.contrast_50 : t.palette.contrast_100, @@ -306,7 +312,7 @@ export function createSharedToggleStyles({ t.name === 'light' ? t.palette.negative_300 : t.palette.negative_800, }) - if (hovered || focused) { + if (hovered) { baseHover.push({ backgroundColor: t.name === 'light' ? t.palette.negative_25 : t.palette.negative_900, @@ -353,7 +359,7 @@ export function Checkbox() { width: 20, }, baseStyles, - hovered || focused ? baseHoverStyles : {}, + hovered ? baseHoverStyles : {}, ]}> {selected ? <Checkmark size="xs" fill={t.palette.primary_500} /> : null} </View> @@ -385,7 +391,7 @@ export function Switch() { width: 30, }, baseStyles, - hovered || focused ? baseHoverStyles : {}, + hovered ? baseHoverStyles : {}, ]}> <View style={[ @@ -437,7 +443,7 @@ export function Radio() { width: 20, }, baseStyles, - hovered || focused ? baseHoverStyles : {}, + hovered ? baseHoverStyles : {}, ]}> {selected ? ( <View diff --git a/src/components/forms/ToggleButton.tsx b/src/components/forms/ToggleButton.tsx index 7e1bd70b9..9cdaaaa9d 100644 --- a/src/components/forms/ToggleButton.tsx +++ b/src/components/forms/ToggleButton.tsx @@ -8,7 +8,9 @@ import * as Toggle from '#/components/forms/Toggle' export type ItemProps = Omit<Toggle.ItemProps, 'style' | 'role' | 'children'> & AccessibilityProps & - React.PropsWithChildren<{testID?: string}> + React.PropsWithChildren<{ + testID?: string + }> export type GroupProps = Omit<Toggle.GroupProps, 'style' | 'type'> & { multiple?: boolean @@ -101,12 +103,12 @@ function ButtonInner({children}: React.PropsWithChildren<{}>) { native({ paddingBottom: 10, }), - a.px_sm, + a.px_md, t.atoms.bg, t.atoms.border_contrast_low, baseStyles, activeStyles, - (state.hovered || state.focused || state.pressed) && hoverStyles, + (state.hovered || state.pressed) && hoverStyles, ]}> {typeof children === 'string' ? ( <Text diff --git a/src/components/hooks/useDelayedLoading.ts b/src/components/hooks/useDelayedLoading.ts new file mode 100644 index 000000000..6c7e2ede0 --- /dev/null +++ b/src/components/hooks/useDelayedLoading.ts @@ -0,0 +1,15 @@ +import React from 'react' + +export function useDelayedLoading(delay: number, initialState: boolean = true) { + const [isLoading, setIsLoading] = React.useState(initialState) + + React.useEffect(() => { + let timeout: NodeJS.Timeout + // on initial load, show a loading spinner for a hot sec to prevent flash + if (isLoading) timeout = setTimeout(() => setIsLoading(false), delay) + + return () => timeout && clearTimeout(timeout) + }, [isLoading, delay]) + + return isLoading +} diff --git a/src/components/icons/ArrowTriangle.tsx b/src/components/icons/ArrowTriangle.tsx new file mode 100644 index 000000000..b27b719ae --- /dev/null +++ b/src/components/icons/ArrowTriangle.tsx @@ -0,0 +1,5 @@ +import {createSinglePathSVG} from './TEMPLATE' + +export const ArrowTriangleBottom_Stroke2_Corner1_Rounded = createSinglePathSVG({ + path: 'M4.213 6.886c-.673-1.35.334-2.889 1.806-2.889H17.98c1.472 0 2.479 1.539 1.806 2.89l-5.982 11.997c-.74 1.484-2.87 1.484-3.61 0L4.213 6.886Z', +}) diff --git a/src/components/icons/Bars.tsx b/src/components/icons/Bars.tsx new file mode 100644 index 000000000..7b1415a4b --- /dev/null +++ b/src/components/icons/Bars.tsx @@ -0,0 +1,5 @@ +import {createSinglePathSVG} from './TEMPLATE' + +export const Bars3_Stroke2_Corner0_Rounded = createSinglePathSVG({ + path: 'M3 5a1 1 0 0 0 0 2h18a1 1 0 1 0 0-2H3Zm-1 7a1 1 0 0 1 1-1h18a1 1 0 1 1 0 2H3a1 1 0 0 1-1-1Zm0 6a1 1 0 0 1 1-1h18a1 1 0 1 1 0 2H3a1 1 0 0 1-1-1Z', +}) diff --git a/src/components/icons/Camera.tsx b/src/components/icons/Camera.tsx new file mode 100644 index 000000000..ced8e7442 --- /dev/null +++ b/src/components/icons/Camera.tsx @@ -0,0 +1,9 @@ +import {createSinglePathSVG} from './TEMPLATE' + +export const Camera_Stroke2_Corner0_Rounded = createSinglePathSVG({ + path: 'M8.371 3.89A2 2 0 0 1 10.035 3h3.93a2 2 0 0 1 1.664.89L17.035 6H20a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h2.965L8.37 3.89ZM13.965 5h-3.93L8.63 7.11A2 2 0 0 1 6.965 8H4v11h16V8h-2.965a2 2 0 0 1-1.664-.89L13.965 5ZM12 11a2 2 0 1 0 0 4 2 2 0 0 0 0-4Zm-4 2a4 4 0 1 1 8 0 4 4 0 0 1-8 0Z', +}) + +export const Camera_Filled_Stroke2_Corner0_Rounded = createSinglePathSVG({ + path: 'M8.371 3.89A2 2 0 0 1 10.035 3h3.93a2 2 0 0 1 1.664.89L17.035 6H20a2 2 0 0 1 2 2v11a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h2.965L8.37 3.89ZM12 9a3.5 3.5 0 1 0 0 7 3.5 3.5 0 0 0 0-7Z', +}) diff --git a/src/components/icons/Chevron.tsx b/src/components/icons/Chevron.tsx index b1a9deea0..a04e6e009 100644 --- a/src/components/icons/Chevron.tsx +++ b/src/components/icons/Chevron.tsx @@ -7,3 +7,11 @@ export const ChevronLeft_Stroke2_Corner0_Rounded = createSinglePathSVG({ export const ChevronRight_Stroke2_Corner0_Rounded = createSinglePathSVG({ path: 'M8.293 3.293a1 1 0 0 1 1.414 0l8 8a1 1 0 0 1 0 1.414l-8 8a1 1 0 0 1-1.414-1.414L15.586 12 8.293 4.707a1 1 0 0 1 0-1.414Z', }) + +export const ChevronTop_Stroke2_Corner0_Rounded = createSinglePathSVG({ + path: 'M12 6a1 1 0 0 1 .707.293l8 8a1 1 0 0 1-1.414 1.414L12 8.414l-7.293 7.293a1 1 0 0 1-1.414-1.414l8-8A1 1 0 0 1 12 6Z', +}) + +export const ChevronBottom_Stroke2_Corner0_Rounded = createSinglePathSVG({ + path: 'M3.293 8.293a1 1 0 0 1 1.414 0L12 15.586l7.293-7.293a1 1 0 1 1 1.414 1.414l-8 8a1 1 0 0 1-1.414 0l-8-8a1 1 0 0 1 0-1.414Z', +}) diff --git a/src/components/icons/CircleBanSign.tsx b/src/components/icons/CircleBanSign.tsx new file mode 100644 index 000000000..543985d43 --- /dev/null +++ b/src/components/icons/CircleBanSign.tsx @@ -0,0 +1,5 @@ +import {createSinglePathSVG} from './TEMPLATE' + +export const CircleBanSign_Stroke2_Corner0_Rounded = createSinglePathSVG({ + path: 'M12 4a8 8 0 0 0-6.32 12.906L16.906 5.68A7.962 7.962 0 0 0 12 4Zm6.32 3.094L7.094 18.32A8 8 0 0 0 18.32 7.094ZM2 12C2 6.477 6.477 2 12 2a9.972 9.972 0 0 1 7.071 2.929A9.972 9.972 0 0 1 22 12c0 5.523-4.477 10-10 10a9.972 9.972 0 0 1-7.071-2.929A9.972 9.972 0 0 1 2 12Z', +}) diff --git a/src/components/icons/DotGrid.tsx b/src/components/icons/DotGrid.tsx new file mode 100644 index 000000000..c50d7a440 --- /dev/null +++ b/src/components/icons/DotGrid.tsx @@ -0,0 +1,5 @@ +import {createSinglePathSVG} from './TEMPLATE' + +export const DotGrid_Stroke2_Corner0_Rounded = createSinglePathSVG({ + path: 'M2 12a2 2 0 1 1 4 0 2 2 0 0 1-4 0Zm16 0a2 2 0 1 1 4 0 2 2 0 0 1-4 0Zm-6-2a2 2 0 1 0 0 4 2 2 0 0 0 0-4Z', +}) diff --git a/src/components/icons/Flag.tsx b/src/components/icons/Flag.tsx new file mode 100644 index 000000000..d986db75a --- /dev/null +++ b/src/components/icons/Flag.tsx @@ -0,0 +1,5 @@ +import {createSinglePathSVG} from './TEMPLATE' + +export const Flag_Stroke2_Corner0_Rounded = createSinglePathSVG({ + path: 'M4 4a2 2 0 0 1 2-2h13.131c1.598 0 2.55 1.78 1.665 3.11L18.202 9l2.594 3.89c.886 1.33-.067 3.11-1.665 3.11H6v5a1 1 0 1 1-2 0V4Zm2 10h13.131l-2.593-3.89a2 2 0 0 1 0-2.22L19.13 4H6v10Z', +}) diff --git a/src/components/icons/Gear.tsx b/src/components/icons/Gear.tsx new file mode 100644 index 000000000..980b7413b --- /dev/null +++ b/src/components/icons/Gear.tsx @@ -0,0 +1,5 @@ +import {createSinglePathSVG} from './TEMPLATE' + +export const SettingsGear2_Stroke2_Corner0_Rounded = createSinglePathSVG({ + path: 'M11.1 2a1 1 0 0 0-.832.445L8.851 4.57 6.6 4.05a1 1 0 0 0-.932.268l-1.35 1.35a1 1 0 0 0-.267.932l.52 2.251-2.126 1.417A1 1 0 0 0 2 11.1v1.8a1 1 0 0 0 .445.832l2.125 1.417-.52 2.251a1 1 0 0 0 .268.932l1.35 1.35a1 1 0 0 0 .932.267l2.251-.52 1.417 2.126A1 1 0 0 0 11.1 22h1.8a1 1 0 0 0 .832-.445l1.417-2.125 2.251.52a1 1 0 0 0 .932-.268l1.35-1.35a1 1 0 0 0 .267-.932l-.52-2.251 2.126-1.417A1 1 0 0 0 22 12.9v-1.8a1 1 0 0 0-.445-.832L19.43 8.851l.52-2.251a1 1 0 0 0-.268-.932l-1.35-1.35a1 1 0 0 0-.932-.267l-2.251.52-1.417-2.126A1 1 0 0 0 12.9 2h-1.8Zm-.968 4.255L11.635 4h.73l1.503 2.255a1 1 0 0 0 1.057.42l2.385-.551.566.566-.55 2.385a1 1 0 0 0 .42 1.057L20 11.635v.73l-2.255 1.503a1 1 0 0 0-.42 1.057l.551 2.385-.566.566-2.385-.55a1 1 0 0 0-1.057.42L12.365 20h-.73l-1.503-2.255a1 1 0 0 0-1.057-.42l-2.385.551-.566-.566.55-2.385a1 1 0 0 0-.42-1.057L4 12.365v-.73l2.255-1.503a1 1 0 0 0 .42-1.057L6.123 6.69l.566-.566 2.385.55a1 1 0 0 0 1.057-.42ZM8 12a4 4 0 1 1 8 0 4 4 0 0 1-8 0Zm4-2a2 2 0 1 0 0 4 2 2 0 0 0 0-4Z', +}) diff --git a/src/components/icons/Group3.tsx b/src/components/icons/Group.tsx index 9e5ab8893..9e5ab8893 100644 --- a/src/components/icons/Group3.tsx +++ b/src/components/icons/Group.tsx diff --git a/src/components/icons/Heart2.tsx b/src/components/icons/Heart2.tsx new file mode 100644 index 000000000..07f5a1d2c --- /dev/null +++ b/src/components/icons/Heart2.tsx @@ -0,0 +1,9 @@ +import {createSinglePathSVG} from './TEMPLATE' + +export const Heart2_Stroke2_Corner0_Rounded = createSinglePathSVG({ + path: 'M16.734 5.091c-1.238-.276-2.708.047-4.022 1.38a1 1 0 0 1-1.424 0C9.974 5.137 8.504 4.814 7.266 5.09c-1.263.282-2.379 1.206-2.92 2.556C3.33 10.18 4.252 14.84 12 19.348c7.747-4.508 8.67-9.168 7.654-11.7-.541-1.351-1.657-2.275-2.92-2.557Zm4.777 1.812c1.604 4-.494 9.69-9.022 14.47a1 1 0 0 1-.978 0C2.983 16.592.885 10.902 2.49 6.902c.779-1.942 2.414-3.334 4.342-3.764 1.697-.378 3.552.003 5.169 1.286 1.617-1.283 3.472-1.664 5.17-1.286 1.927.43 3.562 1.822 4.34 3.764Z', +}) + +export const Heart2_Filled_Stroke2_Corner0_Rounded = createSinglePathSVG({ + path: 'M12.489 21.372c8.528-4.78 10.626-10.47 9.022-14.47-.779-1.941-2.414-3.333-4.342-3.763-1.697-.378-3.552.003-5.169 1.287-1.617-1.284-3.472-1.665-5.17-1.287-1.927.43-3.562 1.822-4.34 3.764-1.605 4 .493 9.69 9.021 14.47a1 1 0 0 0 .978 0Z', +}) diff --git a/src/components/icons/PeopleRemove2.tsx b/src/components/icons/PeopleRemove2.tsx new file mode 100644 index 000000000..3d16ed968 --- /dev/null +++ b/src/components/icons/PeopleRemove2.tsx @@ -0,0 +1,5 @@ +import {createSinglePathSVG} from './TEMPLATE' + +export const PeopleRemove2_Stroke2_Corner0_Rounded = createSinglePathSVG({ + path: 'M10 4a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5ZM5.5 6.5a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0ZM16 11a1 1 0 0 1 1-1h5a1 1 0 1 1 0 2h-5a1 1 0 0 1-1-1ZM3.678 19h12.644c-.71-2.909-3.092-5-6.322-5s-5.613 2.091-6.322 5Zm-2.174.906C1.917 15.521 5.242 12 10 12c4.758 0 8.083 3.521 8.496 7.906A1 1 0 0 1 17.5 21h-15a1 1 0 0 1-.996-1.094Z', +}) diff --git a/src/components/icons/PersonCheck.tsx b/src/components/icons/PersonCheck.tsx new file mode 100644 index 000000000..097271d89 --- /dev/null +++ b/src/components/icons/PersonCheck.tsx @@ -0,0 +1,5 @@ +import {createSinglePathSVG} from './TEMPLATE' + +export const PersonCheck_Stroke2_Corner0_Rounded = createSinglePathSVG({ + path: 'M12 4a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5ZM7.5 6.5a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0ZM5.679 19c.709-2.902 3.079-5 6.321-5a6.69 6.69 0 0 1 2.612.51 1 1 0 0 0 .776-1.844A8.687 8.687 0 0 0 12 12c-4.3 0-7.447 2.884-8.304 6.696-.29 1.29.767 2.304 1.902 2.304H11a1 1 0 1 0 0-2H5.679Zm14.835-4.857a1 1 0 0 1 .344 1.371l-3 5a1 1 0 0 1-1.458.286l-2-1.5a1 1 0 0 1 1.2-1.6l1.113.835 2.43-4.05a1 1 0 0 1 1.372-.342Z', +}) diff --git a/src/components/icons/PersonX.tsx b/src/components/icons/PersonX.tsx new file mode 100644 index 000000000..a015e1376 --- /dev/null +++ b/src/components/icons/PersonX.tsx @@ -0,0 +1,5 @@ +import {createSinglePathSVG} from './TEMPLATE' + +export const PersonX_Stroke2_Corner0_Rounded = createSinglePathSVG({ + path: 'M12 4a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5ZM7.5 6.5a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0ZM5.679 19c.709-2.902 3.079-5 6.321-5 .302 0 .595.018.878.053a1 1 0 0 0 .243-1.985A9.235 9.235 0 0 0 12 12c-4.3 0-7.447 2.884-8.304 6.696-.29 1.29.767 2.304 1.902 2.304H12a1 1 0 1 0 0-2H5.679Zm9.614-3.707a1 1 0 0 1 1.414 0L18 16.586l1.293-1.293a1 1 0 0 1 1.414 1.414L19.414 18l1.293 1.293a1 1 0 0 1-1.414 1.414L18 19.414l-1.293 1.293a1 1 0 0 1-1.414-1.414L16.586 18l-1.293-1.293a1 1 0 0 1 0-1.414Z', +}) diff --git a/src/components/icons/RaisingHand.tsx b/src/components/icons/RaisingHand.tsx new file mode 100644 index 000000000..cd023cb7e --- /dev/null +++ b/src/components/icons/RaisingHand.tsx @@ -0,0 +1,5 @@ +import {createSinglePathSVG} from './TEMPLATE' + +export const RaisingHande4Finger_Stroke2_Corner0_Rounded = createSinglePathSVG({ + path: 'M10.25 4a.75.75 0 0 0-.75.75V11a1 1 0 1 1-2 0V6.75a.75.75 0 0 0-1.5 0V14a6 6 0 0 0 12 0V9a2 2 0 0 0-2 2v1.5a1 1 0 0 1-.684.949l-.628.21A2.469 2.469 0 0 0 13 16a1 1 0 1 1-2 0 4.469 4.469 0 0 1 3-4.22V11c0-.703.181-1.364.5-1.938V5.75a.75.75 0 0 0-1.5 0V9a1 1 0 1 1-2 0V4.75a.75.75 0 0 0-.75-.75Zm2.316-.733A2.75 2.75 0 0 1 16.5 5.75v1.54c.463-.187.97-.29 1.5-.29h1a1 1 0 0 1 1 1v6a8 8 0 1 1-16 0V6.75a2.75 2.75 0 0 1 3.571-2.625 2.751 2.751 0 0 1 4.995-.858Z', +}) diff --git a/src/components/icons/Shield.tsx b/src/components/icons/Shield.tsx new file mode 100644 index 000000000..5038d5c24 --- /dev/null +++ b/src/components/icons/Shield.tsx @@ -0,0 +1,5 @@ +import {createSinglePathSVG} from './TEMPLATE' + +export const Shield_Stroke2_Corner0_Rounded = createSinglePathSVG({ + path: 'M11.675 2.054a1 1 0 0 1 .65 0l8 2.75A1 1 0 0 1 21 5.75v6.162c0 2.807-1.149 4.83-2.813 6.405-1.572 1.488-3.632 2.6-5.555 3.636l-.157.085a1 1 0 0 1-.95 0l-.157-.085c-1.923-1.037-3.983-2.148-5.556-3.636C4.15 16.742 3 14.719 3 11.912V5.75a1 1 0 0 1 .675-.946l8-2.75ZM5 6.464v5.448c0 2.166.851 3.687 2.188 4.952 1.276 1.209 2.964 2.158 4.812 3.157 1.848-1 3.536-1.948 4.813-3.157C18.148 15.6 19 14.078 19 11.912V6.464l-7-2.407-7 2.407Z', +}) diff --git a/src/components/icons/SquareArrowTopRight.tsx b/src/components/icons/SquareArrowTopRight.tsx new file mode 100644 index 000000000..7701e26e5 --- /dev/null +++ b/src/components/icons/SquareArrowTopRight.tsx @@ -0,0 +1,5 @@ +import {createSinglePathSVG} from './TEMPLATE' + +export const SquareArrowTopRight_Stroke2_Corner0_Rounded = createSinglePathSVG({ + path: 'M14 5a1 1 0 1 1 0-2h6a1 1 0 0 1 1 1v6a1 1 0 1 1-2 0V6.414l-7.293 7.293a1 1 0 0 1-1.414-1.414L17.586 5H14ZM3 6a1 1 0 0 1 1-1h5a1 1 0 0 1 0 2H5v12h12v-4a1 1 0 1 1 2 0v5a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V6Z', +}) diff --git a/src/components/icons/SquareBehindSquare4.tsx b/src/components/icons/SquareBehindSquare4.tsx new file mode 100644 index 000000000..425599cbc --- /dev/null +++ b/src/components/icons/SquareBehindSquare4.tsx @@ -0,0 +1,5 @@ +import {createSinglePathSVG} from './TEMPLATE' + +export const SquareBehindSquare4_Stroke2_Corner0_Rounded = createSinglePathSVG({ + path: 'M8 8V3a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v12a1 1 0 0 1-1 1h-5v5a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V9a1 1 0 0 1 1-1h5Zm1 8a1 1 0 0 1-1-1v-5H4v10h10v-4H9Z', +}) diff --git a/src/components/icons/StreamingLive.tsx b/src/components/icons/StreamingLive.tsx new file mode 100644 index 000000000..8ab5099da --- /dev/null +++ b/src/components/icons/StreamingLive.tsx @@ -0,0 +1,5 @@ +import {createSinglePathSVG} from './TEMPLATE' + +export const StreamingLive_Stroke2_Corner0_Rounded = createSinglePathSVG({ + path: 'M4 4a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2H4Zm8 12.5c1.253 0 2.197.609 2.674 1.5H9.326c.477-.891 1.42-1.5 2.674-1.5Zm0-2c2.404 0 4.235 1.475 4.822 3.5H20V6H4v12h3.178c.587-2.025 2.418-3.5 4.822-3.5Zm-1.25-3.75a1.25 1.25 0 1 1 2.5 0 1.25 1.25 0 0 1-2.5 0ZM12 7.5a3.25 3.25 0 1 0 0 6.5 3.25 3.25 0 0 0 0-6.5Zm5.75 2a1.25 1.25 0 1 0 0-2.5 1.25 1.25 0 0 0 0 2.5Z', +}) diff --git a/src/components/moderation/ContentHider.tsx b/src/components/moderation/ContentHider.tsx new file mode 100644 index 000000000..1e8f36d31 --- /dev/null +++ b/src/components/moderation/ContentHider.tsx @@ -0,0 +1,182 @@ +import React from 'react' +import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native' +import {ModerationUI} from '@atproto/api' +import {useLingui} from '@lingui/react' +import {msg, Trans} from '@lingui/macro' + +import {useModerationCauseDescription} from '#/lib/moderation/useModerationCauseDescription' +import {isJustAMute} from '#/lib/moderation' +import {sanitizeDisplayName} from '#/lib/strings/display-names' + +import {atoms as a, useTheme, useBreakpoints, web} from '#/alf' +import {Button} from '#/components/Button' +import {Text} from '#/components/Typography' +import { + ModerationDetailsDialog, + useModerationDetailsDialogControl, +} from '#/components/moderation/ModerationDetailsDialog' + +export function ContentHider({ + testID, + modui, + ignoreMute, + style, + childContainerStyle, + children, +}: React.PropsWithChildren<{ + testID?: string + modui: ModerationUI | undefined + ignoreMute?: boolean + style?: StyleProp<ViewStyle> + childContainerStyle?: StyleProp<ViewStyle> +}>) { + const t = useTheme() + const {_} = useLingui() + const {gtMobile} = useBreakpoints() + const [override, setOverride] = React.useState(false) + const control = useModerationDetailsDialogControl() + + const blur = modui?.blurs[0] + const desc = useModerationCauseDescription(blur) + + if (!blur || (ignoreMute && isJustAMute(modui))) { + return ( + <View testID={testID} style={[styles.outer, style]}> + {children} + </View> + ) + } + + return ( + <View testID={testID} style={[a.overflow_hidden, style]}> + <ModerationDetailsDialog control={control} modcause={blur} /> + + <Button + onPress={() => { + if (!modui.noOverride) { + setOverride(v => !v) + } else { + control.open() + } + }} + label={desc.name} + accessibilityHint={ + modui.noOverride + ? _(msg`Learn more about the moderation applied to this content.`) + : override + ? _(msg`Hide the content`) + : _(msg`Show the content`) + }> + {state => ( + <View + style={[ + a.flex_row, + a.w_full, + a.justify_start, + a.align_center, + a.py_md, + a.px_lg, + a.gap_xs, + a.rounded_sm, + t.atoms.bg_contrast_25, + gtMobile && [a.gap_sm, a.py_lg, a.mt_xs, a.px_xl], + (state.hovered || state.pressed) && t.atoms.bg_contrast_50, + ]}> + <desc.icon + size="md" + fill={t.atoms.text_contrast_medium.color} + style={{marginLeft: -2}} + /> + <Text + style={[ + a.flex_1, + a.text_left, + a.font_bold, + a.leading_snug, + gtMobile && [a.font_semibold], + t.atoms.text_contrast_medium, + web({ + marginBottom: 1, + }), + ]}> + {desc.name} + </Text> + {!modui.noOverride && ( + <Text + style={[ + a.font_bold, + a.leading_snug, + gtMobile && [a.font_semibold], + t.atoms.text_contrast_high, + web({ + marginBottom: 1, + }), + ]}> + {override ? <Trans>Hide</Trans> : <Trans>Show</Trans>} + </Text> + )} + </View> + )} + </Button> + + {desc.source && blur.type === 'label' && !override && ( + <Button + onPress={() => { + control.open() + }} + label={_( + msg`Learn more about the moderation applied to this content.`, + )} + style={[a.pt_sm]}> + {state => ( + <Text + style={[ + a.flex_1, + a.text_sm, + a.font_normal, + a.leading_snug, + t.atoms.text_contrast_medium, + a.text_left, + ]}> + {desc.sourceType === 'user' ? ( + <Trans>Labeled by the author.</Trans> + ) : ( + <Trans>Labeled by {sanitizeDisplayName(desc.source!)}.</Trans> + )}{' '} + <Text + style={[ + {color: t.palette.primary_500}, + a.text_sm, + state.hovered && [web({textDecoration: 'underline'})], + ]}> + <Trans>Learn more.</Trans> + </Text> + </Text> + )} + </Button> + )} + + {override && <View style={childContainerStyle}>{children}</View>} + </View> + ) +} + +const styles = StyleSheet.create({ + outer: { + overflow: 'hidden', + }, + cover: { + flexDirection: 'row', + alignItems: 'center', + gap: 6, + borderRadius: 8, + marginTop: 4, + paddingVertical: 14, + paddingLeft: 14, + paddingRight: 18, + }, + showBtn: { + marginLeft: 'auto', + alignSelf: 'center', + }, +}) diff --git a/src/components/moderation/GlobalModerationLabelPref.tsx b/src/components/moderation/GlobalModerationLabelPref.tsx new file mode 100644 index 000000000..7633cb9f2 --- /dev/null +++ b/src/components/moderation/GlobalModerationLabelPref.tsx @@ -0,0 +1,93 @@ +import React from 'react' +import {View} from 'react-native' +import {InterpretedLabelValueDefinition, LabelPreference} from '@atproto/api' +import {useLingui} from '@lingui/react' +import {msg} from '@lingui/macro' + +import {useGlobalLabelStrings} from '#/lib/moderation/useGlobalLabelStrings' +import { + usePreferencesQuery, + usePreferencesSetContentLabelMutation, +} from '#/state/queries/preferences' + +import {useTheme, atoms as a} from '#/alf' +import {Text} from '#/components/Typography' +import * as ToggleButton from '#/components/forms/ToggleButton' + +export function GlobalModerationLabelPref({ + labelValueDefinition, + disabled, +}: { + labelValueDefinition: InterpretedLabelValueDefinition + disabled?: boolean +}) { + const {_} = useLingui() + const t = useTheme() + + const {identifier} = labelValueDefinition + const {data: preferences} = usePreferencesQuery() + const {mutate, variables} = usePreferencesSetContentLabelMutation() + const savedPref = preferences?.moderationPrefs.labels[identifier] + const pref = variables?.visibility ?? savedPref ?? 'warn' + + const allLabelStrings = useGlobalLabelStrings() + const labelStrings = + labelValueDefinition.identifier in allLabelStrings + ? allLabelStrings[labelValueDefinition.identifier] + : { + name: labelValueDefinition.identifier, + description: `Labeled "${labelValueDefinition.identifier}"`, + } + + const labelOptions = { + hide: _(msg`Hide`), + warn: _(msg`Warn`), + ignore: _(msg`Show`), + } + + return ( + <View + style={[ + a.flex_row, + a.justify_between, + a.gap_sm, + a.py_md, + a.pl_lg, + a.pr_md, + a.align_center, + ]}> + <View style={[a.gap_xs, a.flex_1]}> + <Text style={[a.font_bold]}>{labelStrings.name}</Text> + <Text style={[t.atoms.text_contrast_medium, a.leading_snug]}> + {labelStrings.description} + </Text> + </View> + <View style={[a.justify_center, {minHeight: 35}]}> + {!disabled && ( + <ToggleButton.Group + label={_( + msg`Configure content filtering setting for category: ${labelStrings.name.toLowerCase()}`, + )} + values={[pref]} + onChange={newPref => + mutate({ + label: identifier, + visibility: newPref[0] as LabelPreference, + labelerDid: undefined, + }) + }> + <ToggleButton.Button name="ignore" label={labelOptions.ignore}> + {labelOptions.ignore} + </ToggleButton.Button> + <ToggleButton.Button name="warn" label={labelOptions.warn}> + {labelOptions.warn} + </ToggleButton.Button> + <ToggleButton.Button name="hide" label={labelOptions.hide}> + {labelOptions.hide} + </ToggleButton.Button> + </ToggleButton.Group> + )} + </View> + </View> + ) +} diff --git a/src/components/moderation/LabelsOnMe.tsx b/src/components/moderation/LabelsOnMe.tsx new file mode 100644 index 000000000..099769fa7 --- /dev/null +++ b/src/components/moderation/LabelsOnMe.tsx @@ -0,0 +1,83 @@ +import React from 'react' +import {StyleProp, View, ViewStyle} from 'react-native' +import {AppBskyFeedDefs, ComAtprotoLabelDefs} from '@atproto/api' +import {msg, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {useSession} from '#/state/session' + +import {atoms as a} from '#/alf' +import {Button, ButtonText, ButtonIcon, ButtonSize} from '#/components/Button' +import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo' +import { + LabelsOnMeDialog, + useLabelsOnMeDialogControl, +} from '#/components/moderation/LabelsOnMeDialog' + +export function LabelsOnMe({ + details, + labels, + size, + style, +}: { + details: {did: string} | {uri: string; cid: string} + labels: ComAtprotoLabelDefs.Label[] | undefined + size?: ButtonSize + style?: StyleProp<ViewStyle> +}) { + const {_} = useLingui() + const {currentAccount} = useSession() + const isAccount = 'did' in details + const control = useLabelsOnMeDialogControl() + + if (!labels || !currentAccount) { + return null + } + labels = labels.filter( + l => !l.val.startsWith('!') && l.src !== currentAccount.did, + ) + if (!labels.length) { + return null + } + + const labelTarget = isAccount ? _(msg`account`) : _(msg`content`) + return ( + <View style={[a.flex_row, style]}> + <LabelsOnMeDialog control={control} subject={details} labels={labels} /> + + <Button + variant="solid" + color="secondary" + size={size || 'small'} + label={_(msg`View information about these labels`)} + onPress={() => { + control.open() + }}> + <ButtonIcon position="left" icon={CircleInfo} /> + <ButtonText style={[a.leading_snug]}> + {labels.length}{' '} + {labels.length === 1 ? ( + <Trans>label has been placed on this {labelTarget}</Trans> + ) : ( + <Trans>labels have been placed on this {labelTarget}</Trans> + )} + </ButtonText> + </Button> + </View> + ) +} + +export function LabelsOnMyPost({ + post, + style, +}: { + post: AppBskyFeedDefs.PostView + style?: StyleProp<ViewStyle> +}) { + const {currentAccount} = useSession() + if (post.author.did !== currentAccount?.did) { + return null + } + return ( + <LabelsOnMe details={post} labels={post.labels} size="tiny" style={style} /> + ) +} diff --git a/src/components/moderation/LabelsOnMeDialog.tsx b/src/components/moderation/LabelsOnMeDialog.tsx new file mode 100644 index 000000000..6eddbc7ce --- /dev/null +++ b/src/components/moderation/LabelsOnMeDialog.tsx @@ -0,0 +1,262 @@ +import React from 'react' +import {View} from 'react-native' +import {msg, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {ComAtprotoLabelDefs, ComAtprotoModerationDefs} from '@atproto/api' + +import {useLabelInfo} from '#/lib/moderation/useLabelInfo' +import {makeProfileLink} from '#/lib/routes/links' +import {sanitizeHandle} from '#/lib/strings/handles' +import {getAgent} from '#/state/session' + +import {atoms as a, useBreakpoints, useTheme} from '#/alf' +import {Text} from '#/components/Typography' +import * as Dialog from '#/components/Dialog' +import {Button, ButtonText} from '#/components/Button' +import {InlineLink} from '#/components/Link' +import * as Toast from '#/view/com/util/Toast' +import {Divider} from '../Divider' + +export {useDialogControl as useLabelsOnMeDialogControl} from '#/components/Dialog' + +type Subject = + | { + uri: string + cid: string + } + | { + did: string + } + +export interface LabelsOnMeDialogProps { + control: Dialog.DialogOuterProps['control'] + subject: Subject + labels: ComAtprotoLabelDefs.Label[] +} + +export function LabelsOnMeDialogInner(props: LabelsOnMeDialogProps) { + const {_} = useLingui() + const [appealingLabel, setAppealingLabel] = React.useState< + ComAtprotoLabelDefs.Label | undefined + >(undefined) + const {subject, labels} = props + const isAccount = 'did' in subject + + return ( + <Dialog.ScrollableInner + label={ + isAccount + ? _(msg`The following labels were applied to your account.`) + : _(msg`The following labels were applied to your content.`) + }> + {appealingLabel ? ( + <AppealForm + label={appealingLabel} + subject={subject} + control={props.control} + onPressBack={() => setAppealingLabel(undefined)} + /> + ) : ( + <> + <Text style={[a.text_2xl, a.font_bold, a.pb_xs, a.leading_tight]}> + {isAccount ? ( + <Trans>Labels on your account</Trans> + ) : ( + <Trans>Labels on your content</Trans> + )} + </Text> + <Text style={[a.text_md, a.leading_snug]}> + <Trans> + You may appeal these labels if you feel they were placed in error. + </Trans> + </Text> + + <View style={[a.py_lg, a.gap_md]}> + {labels.map(label => ( + <Label + key={`${label.val}-${label.src}`} + label={label} + control={props.control} + onPressAppeal={label => setAppealingLabel(label)} + /> + ))} + </View> + </> + )} + + <Dialog.Close /> + </Dialog.ScrollableInner> + ) +} + +export function LabelsOnMeDialog(props: LabelsOnMeDialogProps) { + return ( + <Dialog.Outer control={props.control}> + <Dialog.Handle /> + + <LabelsOnMeDialogInner {...props} /> + </Dialog.Outer> + ) +} + +function Label({ + label, + control, + onPressAppeal, +}: { + label: ComAtprotoLabelDefs.Label + control: Dialog.DialogOuterProps['control'] + onPressAppeal: (label: ComAtprotoLabelDefs.Label) => void +}) { + const t = useTheme() + const {_} = useLingui() + const {labeler, strings} = useLabelInfo(label) + return ( + <View + style={[ + a.border, + t.atoms.border_contrast_low, + a.rounded_sm, + a.overflow_hidden, + ]}> + <View style={[a.p_md, a.gap_sm, a.flex_row]}> + <View style={[a.flex_1, a.gap_xs]}> + <Text style={[a.font_bold, a.text_md]}>{strings.name}</Text> + <Text style={[t.atoms.text_contrast_medium, a.leading_snug]}> + {strings.description} + </Text> + </View> + <View> + <Button + variant="solid" + color="secondary" + size="small" + label={_(msg`Appeal`)} + onPress={() => onPressAppeal(label)}> + <ButtonText> + <Trans>Appeal</Trans> + </ButtonText> + </Button> + </View> + </View> + + <Divider /> + + <View style={[a.px_md, a.py_sm, t.atoms.bg_contrast_25]}> + <Text style={[t.atoms.text_contrast_medium]}> + <Trans>Source:</Trans>{' '} + <InlineLink + to={makeProfileLink( + labeler ? labeler.creator : {did: label.src, handle: ''}, + )} + onPress={() => control.close()}> + {labeler ? sanitizeHandle(labeler.creator.handle, '@') : label.src} + </InlineLink> + </Text> + </View> + </View> + ) +} + +function AppealForm({ + label, + subject, + control, + onPressBack, +}: { + label: ComAtprotoLabelDefs.Label + subject: Subject + control: Dialog.DialogOuterProps['control'] + onPressBack: () => void +}) { + const {_} = useLingui() + const {labeler, strings} = useLabelInfo(label) + const {gtMobile} = useBreakpoints() + const [details, setDetails] = React.useState('') + const isAccountReport = 'did' in subject + + const onSubmit = async () => { + try { + const $type = !isAccountReport + ? 'com.atproto.repo.strongRef' + : 'com.atproto.admin.defs#repoRef' + await getAgent() + .withProxy('atproto_labeler', label.src) + .createModerationReport({ + reasonType: ComAtprotoModerationDefs.REASONAPPEAL, + subject: { + $type, + ...subject, + }, + reason: details, + }) + Toast.show(_(msg`Appeal submitted.`)) + } finally { + control.close() + } + } + + return ( + <> + <Text style={[a.text_2xl, a.font_bold, a.pb_xs, a.leading_tight]}> + <Trans>Appeal "{strings.name}" label</Trans> + </Text> + <Text style={[a.text_md, a.leading_snug]}> + <Trans> + This appeal will be sent to{' '} + <InlineLink + to={makeProfileLink( + labeler ? labeler.creator : {did: label.src, handle: ''}, + )} + onPress={() => control.close()} + style={[a.text_md, a.leading_snug]}> + {labeler ? sanitizeHandle(labeler.creator.handle, '@') : label.src} + </InlineLink> + . + </Trans> + </Text> + <View style={[a.my_md]}> + <Dialog.Input + label={_(msg`Text input field`)} + placeholder={_( + msg`Please explain why you think this label was incorrectly applied by ${ + labeler ? sanitizeHandle(labeler.creator.handle, '@') : label.src + }`, + )} + value={details} + onChangeText={setDetails} + autoFocus={true} + numberOfLines={3} + multiline + maxLength={300} + /> + </View> + + <View + style={ + gtMobile + ? [a.flex_row, a.justify_between] + : [{flexDirection: 'column-reverse'}, a.gap_sm] + }> + <Button + testID="backBtn" + variant="solid" + color="secondary" + size="medium" + onPress={onPressBack} + label={_(msg`Back`)}> + {_(msg`Back`)} + </Button> + <Button + testID="submitBtn" + variant="solid" + color="primary" + size="medium" + onPress={onSubmit} + label={_(msg`Submit`)}> + {_(msg`Submit`)} + </Button> + </View> + </> + ) +} diff --git a/src/components/moderation/ModerationDetailsDialog.tsx b/src/components/moderation/ModerationDetailsDialog.tsx new file mode 100644 index 000000000..da490cb43 --- /dev/null +++ b/src/components/moderation/ModerationDetailsDialog.tsx @@ -0,0 +1,148 @@ +import React from 'react' +import {View} from 'react-native' +import {msg, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {ModerationCause} from '@atproto/api' + +import {listUriToHref} from '#/lib/strings/url-helpers' +import {useModerationCauseDescription} from '#/lib/moderation/useModerationCauseDescription' +import {makeProfileLink} from '#/lib/routes/links' + +import {isNative} from '#/platform/detection' +import {useTheme, atoms as a} from '#/alf' +import {Text} from '#/components/Typography' +import * as Dialog from '#/components/Dialog' +import {InlineLink} from '#/components/Link' +import {Divider} from '#/components/Divider' + +export {useDialogControl as useModerationDetailsDialogControl} from '#/components/Dialog' + +export interface ModerationDetailsDialogProps { + control: Dialog.DialogOuterProps['control'] + modcause: ModerationCause +} + +export function ModerationDetailsDialog(props: ModerationDetailsDialogProps) { + return ( + <Dialog.Outer control={props.control}> + <Dialog.Handle /> + <ModerationDetailsDialogInner {...props} /> + </Dialog.Outer> + ) +} + +function ModerationDetailsDialogInner({ + modcause, + control, +}: ModerationDetailsDialogProps & { + control: Dialog.DialogOuterProps['control'] +}) { + const t = useTheme() + const {_} = useLingui() + const desc = useModerationCauseDescription(modcause) + + let name + let description + if (!modcause) { + name = _(msg`Content Warning`) + description = _( + msg`Moderator has chosen to set a general warning on the content.`, + ) + } else if (modcause.type === 'blocking') { + if (modcause.source.type === 'list') { + const list = modcause.source.list + name = _(msg`User Blocked by List`) + description = ( + <Trans> + This user is included in the{' '} + <InlineLink to={listUriToHref(list.uri)} style={[a.text_sm]}> + {list.name} + </InlineLink>{' '} + list which you have blocked. + </Trans> + ) + } else { + name = _(msg`User Blocked`) + description = _( + msg`You have blocked this user. You cannot view their content.`, + ) + } + } else if (modcause.type === 'blocked-by') { + name = _(msg`User Blocks You`) + description = _( + msg`This user has blocked you. You cannot view their content.`, + ) + } else if (modcause.type === 'block-other') { + name = _(msg`Content Not Available`) + description = _( + msg`This content is not available because one of the users involved has blocked the other.`, + ) + } else if (modcause.type === 'muted') { + if (modcause.source.type === 'list') { + const list = modcause.source.list + name = _(msg`Account Muted by List`) + description = ( + <Trans> + This user is included in the{' '} + <InlineLink to={listUriToHref(list.uri)} style={[a.text_sm]}> + {list.name} + </InlineLink>{' '} + list which you have muted. + </Trans> + ) + } else { + name = _(msg`Account Muted`) + description = _(msg`You have muted this account.`) + } + } else if (modcause.type === 'mute-word') { + name = _(msg`Post Hidden by Muted Word`) + description = _(msg`You've chosen to hide a word or tag within this post.`) + } else if (modcause.type === 'hidden') { + name = _(msg`Post Hidden by You`) + description = _(msg`You have hidden this post.`) + } else if (modcause.type === 'label') { + name = desc.name + description = desc.description + } else { + // should never happen + name = '' + description = '' + } + + return ( + <Dialog.ScrollableInner label={_(msg`Moderation details`)}> + <Text style={[t.atoms.text, a.text_2xl, a.font_bold, a.mb_sm]}> + {name} + </Text> + <Text style={[t.atoms.text, a.text_md, a.mb_lg, a.leading_snug]}> + {description} + </Text> + + {modcause.type === 'label' && ( + <> + <Divider /> + <Text style={[t.atoms.text, a.text_md, a.leading_snug, a.mt_lg]}> + <Trans> + This label was applied by{' '} + {modcause.source.type === 'user' ? ( + <Trans>the author</Trans> + ) : ( + <InlineLink + to={makeProfileLink({did: modcause.label.src, handle: ''})} + onPress={() => control.close()} + style={a.text_md}> + {desc.source} + </InlineLink> + )} + . + </Trans> + </Text> + </> + )} + + {isNative && <View style={{height: 40}} />} + + <Dialog.Close /> + </Dialog.ScrollableInner> + ) +} diff --git a/src/components/moderation/ModerationLabelPref.tsx b/src/components/moderation/ModerationLabelPref.tsx new file mode 100644 index 000000000..b16c24859 --- /dev/null +++ b/src/components/moderation/ModerationLabelPref.tsx @@ -0,0 +1,177 @@ +import React from 'react' +import {View} from 'react-native' +import {InterpretedLabelValueDefinition, LabelPreference} from '@atproto/api' +import {useLingui} from '@lingui/react' +import {msg, Trans} from '@lingui/macro' + +import {useGlobalLabelStrings} from '#/lib/moderation/useGlobalLabelStrings' +import {useLabelBehaviorDescription} from '#/lib/moderation/useLabelBehaviorDescription' +import { + usePreferencesQuery, + usePreferencesSetContentLabelMutation, +} from '#/state/queries/preferences' +import {getLabelStrings} from '#/lib/moderation/useLabelInfo' + +import {useTheme, atoms as a, useBreakpoints} from '#/alf' +import {Text} from '#/components/Typography' +import {InlineLink} from '#/components/Link' +import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '../icons/CircleInfo' +import * as ToggleButton from '#/components/forms/ToggleButton' + +export function ModerationLabelPref({ + labelValueDefinition, + labelerDid, + disabled, +}: { + labelValueDefinition: InterpretedLabelValueDefinition + labelerDid: string | undefined + disabled?: boolean +}) { + const {_, i18n} = useLingui() + const t = useTheme() + const {gtPhone} = useBreakpoints() + + const isGlobalLabel = !labelValueDefinition.definedBy + const {identifier} = labelValueDefinition + const {data: preferences} = usePreferencesQuery() + const {mutate, variables} = usePreferencesSetContentLabelMutation() + const savedPref = + labelerDid && !isGlobalLabel + ? preferences?.moderationPrefs.labelers.find(l => l.did === labelerDid) + ?.labels[identifier] + : preferences?.moderationPrefs.labels[identifier] + const pref = + variables?.visibility ?? + savedPref ?? + labelValueDefinition.defaultSetting ?? + 'warn' + + // does the 'warn' setting make sense for this label? + const canWarn = !( + labelValueDefinition.blurs === 'none' && + labelValueDefinition.severity === 'none' + ) + // is this label adult only? + const adultOnly = labelValueDefinition.flags.includes('adult') + // is this label disabled because it's adult only? + const adultDisabled = + adultOnly && !preferences?.moderationPrefs.adultContentEnabled + // are there any reasons we cant configure this label here? + const cantConfigure = isGlobalLabel || adultDisabled + const showConfig = !disabled && (gtPhone || !cantConfigure) + + // adjust the pref based on whether warn is available + let prefAdjusted = pref + if (adultDisabled) { + prefAdjusted = 'hide' + } else if (!canWarn && pref === 'warn') { + prefAdjusted = 'ignore' + } + + // grab localized descriptions of the label and its settings + const currentPrefLabel = useLabelBehaviorDescription( + labelValueDefinition, + prefAdjusted, + ) + const hideLabel = useLabelBehaviorDescription(labelValueDefinition, 'hide') + const warnLabel = useLabelBehaviorDescription(labelValueDefinition, 'warn') + const ignoreLabel = useLabelBehaviorDescription( + labelValueDefinition, + 'ignore', + ) + const globalLabelStrings = useGlobalLabelStrings() + const labelStrings = getLabelStrings( + i18n.locale, + globalLabelStrings, + labelValueDefinition, + ) + + return ( + <View + style={[ + a.flex_row, + a.gap_md, + a.px_lg, + a.py_lg, + a.justify_between, + a.flex_wrap, + ]}> + <View style={[a.gap_xs, a.flex_1]}> + <Text style={[a.font_bold, gtPhone ? a.text_sm : a.text_md]}> + {labelStrings.name} + </Text> + <Text style={[t.atoms.text_contrast_medium, a.leading_snug]}> + {labelStrings.description} + </Text> + + {cantConfigure && ( + <View style={[a.flex_row, a.gap_xs, a.align_center, a.mt_xs]}> + <CircleInfo size="sm" fill={t.atoms.text_contrast_high.color} /> + + <Text + style={[t.atoms.text_contrast_medium, a.font_semibold, a.italic]}> + {adultDisabled ? ( + <Trans>Adult content is disabled.</Trans> + ) : isGlobalLabel ? ( + <Trans> + Configured in{' '} + <InlineLink to="/moderation" style={a.text_sm}> + moderation settings + </InlineLink> + . + </Trans> + ) : null} + </Text> + </View> + )} + </View> + + {showConfig && ( + <View style={[gtPhone ? undefined : a.w_full]}> + {cantConfigure ? ( + <View + style={[ + {minHeight: 35}, + a.px_md, + a.py_md, + a.rounded_sm, + a.border, + t.atoms.border_contrast_low, + ]}> + <Text style={[a.font_bold, t.atoms.text_contrast_low]}> + {currentPrefLabel} + </Text> + </View> + ) : ( + <View style={[{minHeight: 35}]}> + <ToggleButton.Group + label={_( + msg`Configure content filtering setting for category: ${labelStrings.name.toLowerCase()}`, + )} + values={[prefAdjusted]} + onChange={newPref => + mutate({ + label: identifier, + visibility: newPref[0] as LabelPreference, + labelerDid, + }) + }> + <ToggleButton.Button name="ignore" label={ignoreLabel}> + {ignoreLabel} + </ToggleButton.Button> + {canWarn && ( + <ToggleButton.Button name="warn" label={warnLabel}> + {warnLabel} + </ToggleButton.Button> + )} + <ToggleButton.Button name="hide" label={hideLabel}> + {hideLabel} + </ToggleButton.Button> + </ToggleButton.Group> + </View> + )} + </View> + )} + </View> + ) +} diff --git a/src/components/moderation/PostAlerts.tsx b/src/components/moderation/PostAlerts.tsx new file mode 100644 index 000000000..0bfe69678 --- /dev/null +++ b/src/components/moderation/PostAlerts.tsx @@ -0,0 +1,66 @@ +import React from 'react' +import {StyleProp, View, ViewStyle} from 'react-native' +import {ModerationUI, ModerationCause} from '@atproto/api' + +import {useModerationCauseDescription} from '#/lib/moderation/useModerationCauseDescription' +import {getModerationCauseKey} from '#/lib/moderation' + +import {atoms as a} from '#/alf' +import {Button, ButtonText, ButtonIcon} from '#/components/Button' +import { + ModerationDetailsDialog, + useModerationDetailsDialogControl, +} from '#/components/moderation/ModerationDetailsDialog' + +export function PostAlerts({ + modui, + style, +}: { + modui: ModerationUI + includeMute?: boolean + style?: StyleProp<ViewStyle> +}) { + if (!modui.alert && !modui.inform) { + return null + } + + return ( + <View style={[a.flex_col, a.gap_xs, style]}> + <View style={[a.flex_row, a.flex_wrap, a.gap_xs]}> + {modui.alerts.map(cause => ( + <PostLabel key={getModerationCauseKey(cause)} cause={cause} /> + ))} + {modui.informs.map(cause => ( + <PostLabel key={getModerationCauseKey(cause)} cause={cause} /> + ))} + </View> + </View> + ) +} + +function PostLabel({cause}: {cause: ModerationCause}) { + const control = useModerationDetailsDialogControl() + const desc = useModerationCauseDescription(cause) + + return ( + <> + <Button + label={desc.name} + variant="solid" + color="secondary" + size="small" + shape="default" + onPress={() => { + control.open() + }} + style={[a.px_sm, a.py_xs, a.gap_xs]}> + <ButtonIcon icon={desc.icon} position="left" /> + <ButtonText style={[a.text_left, a.leading_snug]}> + {desc.name} + </ButtonText> + </Button> + + <ModerationDetailsDialog control={control} modcause={cause} /> + </> + ) +} diff --git a/src/view/com/util/moderation/PostHider.tsx b/src/components/moderation/PostHider.tsx index ede62e988..464ee2077 100644 --- a/src/view/com/util/moderation/PostHider.tsx +++ b/src/components/moderation/PostHider.tsx @@ -1,45 +1,50 @@ import React, {ComponentProps} from 'react' import {StyleSheet, Pressable, View, ViewStyle, StyleProp} from 'react-native' import {ModerationUI} from '@atproto/api' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' -import {usePalette} from 'lib/hooks/usePalette' -import {Link} from '../Link' -import {Text} from '../text/Text' -import {addStyle} from 'lib/styles' -import {describeModerationCause} from 'lib/moderation' -import {ShieldExclamation} from 'lib/icons' import {useLingui} from '@lingui/react' import {Trans, msg} from '@lingui/macro' -import {useModalControls} from '#/state/modals' + +import {useModerationCauseDescription} from '#/lib/moderation/useModerationCauseDescription' +import {addStyle} from 'lib/styles' + +import {useTheme, atoms as a} from '#/alf' +import { + ModerationDetailsDialog, + useModerationDetailsDialogControl, +} from '#/components/moderation/ModerationDetailsDialog' +import {Text} from '#/components/Typography' +// import {Link} from '#/components/Link' TODO this imposes some styles that screw things up +import {Link} from '#/view/com/util/Link' interface Props extends ComponentProps<typeof Link> { iconSize: number iconStyles: StyleProp<ViewStyle> - moderation: ModerationUI + modui: ModerationUI } export function PostHider({ testID, href, - moderation, + modui, style, children, iconSize, iconStyles, ...props }: Props) { - const pal = usePalette('default') + const t = useTheme() const {_} = useLingui() const [override, setOverride] = React.useState(false) - const {openModal} = useModalControls() + const control = useModerationDetailsDialogControl() + const blur = modui.blurs[0] + const desc = useModerationCauseDescription(blur) - if (!moderation.blur) { + if (!blur) { return ( <Link testID={testID} style={style} href={href} - noFeedback accessible={false} {...props}> {children} @@ -47,12 +52,10 @@ export function PostHider({ ) } - const isMute = ['muted', 'muted-word'].includes(moderation.cause?.type || '') - const desc = describeModerationCause(moderation.cause, 'content') return !override ? ( <Pressable onPress={() => { - if (!moderation.noOverride) { + if (!modui.noOverride) { setOverride(v => !v) } }} @@ -62,49 +65,45 @@ export function PostHider({ } accessibilityLabel="" style={[ - styles.description, + a.flex_row, + a.align_center, + a.gap_sm, + a.py_md, + { + paddingLeft: 6, + paddingRight: 18, + }, override ? {paddingBottom: 0} : undefined, - pal.view, + t.atoms.bg, ]}> + <ModerationDetailsDialog control={control} modcause={blur} /> <Pressable onPress={() => { - openModal({ - name: 'moderation-details', - context: 'content', - moderation, - }) + control.open() }} accessibilityRole="button" accessibilityLabel={_(msg`Learn more about this warning`)} accessibilityHint=""> <View style={[ - pal.viewLight, + t.atoms.bg_contrast_25, + a.align_center, + a.justify_center, { width: iconSize, height: iconSize, borderRadius: iconSize, - alignItems: 'center', - justifyContent: 'center', }, iconStyles, ]}> - {isMute ? ( - <FontAwesomeIcon - icon={['far', 'eye-slash']} - size={14} - color={pal.colors.textLight} - /> - ) : ( - <ShieldExclamation size={14} style={pal.textLight} /> - )} + <desc.icon size="sm" fill={t.atoms.text_contrast_medium.color} /> </View> </Pressable> - <Text type="sm" style={[{flex: 1}, pal.textLight]} numberOfLines={1}> + <Text style={[t.atoms.text_contrast_medium, a.flex_1]} numberOfLines={1}> {desc.name} </Text> - {!moderation.noOverride && ( - <Text type="sm" style={[styles.showBtn, pal.link]}> + {!modui.noOverride && ( + <Text style={[{color: t.palette.primary_500}]}> {override ? <Trans>Hide</Trans> : <Trans>Show</Trans>} </Text> )} @@ -114,26 +113,14 @@ export function PostHider({ testID={testID} style={addStyle(style, styles.child)} href={href} - noFeedback> + accessible={false} + {...props}> {children} </Link> ) } const styles = StyleSheet.create({ - description: { - flexDirection: 'row', - alignItems: 'center', - gap: 4, - paddingVertical: 10, - paddingLeft: 6, - paddingRight: 18, - marginTop: 1, - }, - showBtn: { - marginLeft: 'auto', - alignSelf: 'center', - }, child: { borderWidth: 0, borderTopWidth: 0, diff --git a/src/components/moderation/ProfileHeaderAlerts.tsx b/src/components/moderation/ProfileHeaderAlerts.tsx new file mode 100644 index 000000000..dfc2aa557 --- /dev/null +++ b/src/components/moderation/ProfileHeaderAlerts.tsx @@ -0,0 +1,66 @@ +import React from 'react' +import {StyleProp, View, ViewStyle} from 'react-native' +import {ModerationCause, ModerationDecision} from '@atproto/api' + +import {getModerationCauseKey} from 'lib/moderation' +import {useModerationCauseDescription} from '#/lib/moderation/useModerationCauseDescription' + +import {atoms as a} from '#/alf' +import {Button, ButtonText, ButtonIcon} from '#/components/Button' +import { + ModerationDetailsDialog, + useModerationDetailsDialogControl, +} from '#/components/moderation/ModerationDetailsDialog' + +export function ProfileHeaderAlerts({ + moderation, + style, +}: { + moderation: ModerationDecision + style?: StyleProp<ViewStyle> +}) { + const modui = moderation.ui('profileView') + if (!modui.alert && !modui.inform) { + return null + } + + return ( + <View style={[a.flex_col, a.gap_xs, style]}> + <View style={[a.flex_row, a.flex_wrap, a.gap_xs]}> + {modui.alerts.map(cause => ( + <ProfileLabel key={getModerationCauseKey(cause)} cause={cause} /> + ))} + {modui.informs.map(cause => ( + <ProfileLabel key={getModerationCauseKey(cause)} cause={cause} /> + ))} + </View> + </View> + ) +} + +function ProfileLabel({cause}: {cause: ModerationCause}) { + const control = useModerationDetailsDialogControl() + const desc = useModerationCauseDescription(cause) + + return ( + <> + <Button + label={desc.name} + variant="solid" + color="secondary" + size="small" + shape="default" + onPress={() => { + control.open() + }} + style={[a.px_sm, a.py_xs, a.gap_xs]}> + <ButtonIcon icon={desc.icon} position="left" /> + <ButtonText style={[a.text_left, a.leading_snug]}> + {desc.name} + </ButtonText> + </Button> + + <ModerationDetailsDialog control={control} modcause={cause} /> + </> + ) +} diff --git a/src/components/moderation/ScreenHider.tsx b/src/components/moderation/ScreenHider.tsx new file mode 100644 index 000000000..71ca85a92 --- /dev/null +++ b/src/components/moderation/ScreenHider.tsx @@ -0,0 +1,171 @@ +import React from 'react' +import { + TouchableWithoutFeedback, + StyleProp, + View, + ViewStyle, +} from 'react-native' +import {useNavigation} from '@react-navigation/native' +import {ModerationUI} from '@atproto/api' +import {Trans, msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' + +import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' +import {NavigationProp} from 'lib/routes/types' +import {useModerationCauseDescription} from '#/lib/moderation/useModerationCauseDescription' + +import {useTheme, atoms as a} from '#/alf' +import {CenteredView} from '#/view/com/util/Views' +import {Text} from '#/components/Typography' +import {Button, ButtonText} from '#/components/Button' +import { + ModerationDetailsDialog, + useModerationDetailsDialogControl, +} from '#/components/moderation/ModerationDetailsDialog' + +export function ScreenHider({ + testID, + screenDescription, + modui, + style, + containerStyle, + children, +}: React.PropsWithChildren<{ + testID?: string + screenDescription: string + modui: ModerationUI + style?: StyleProp<ViewStyle> + containerStyle?: StyleProp<ViewStyle> +}>) { + const t = useTheme() + const {_} = useLingui() + const [override, setOverride] = React.useState(false) + const navigation = useNavigation<NavigationProp>() + const {isMobile} = useWebMediaQueries() + const control = useModerationDetailsDialogControl() + const blur = modui.blurs[0] + const desc = useModerationCauseDescription(blur) + + if (!blur || override) { + return ( + <View testID={testID} style={style}> + {children} + </View> + ) + } + + const isNoPwi = !!modui.blurs.find( + cause => + cause.type === 'label' && cause.labelDef.id === '!no-unauthenticated', + ) + return ( + <CenteredView + style={[ + a.flex_1, + { + paddingTop: 100, + paddingBottom: 150, + }, + t.atoms.bg, + containerStyle, + ]} + sideBorders> + <View style={[a.align_center, a.mb_md]}> + <View + style={[ + t.atoms.bg_contrast_975, + a.align_center, + a.justify_center, + { + borderRadius: 25, + width: 50, + height: 50, + }, + ]}> + <desc.icon width={24} fill={t.atoms.bg.backgroundColor} /> + </View> + </View> + <Text + style={[ + a.text_4xl, + a.font_semibold, + a.text_center, + a.mb_md, + t.atoms.text, + ]}> + {isNoPwi ? ( + <Trans>Sign-in Required</Trans> + ) : ( + <Trans>Content Warning</Trans> + )} + </Text> + <Text + style={[ + a.text_lg, + a.mb_md, + a.px_lg, + a.text_center, + t.atoms.text_contrast_medium, + ]}> + {isNoPwi ? ( + <Trans> + This account has requested that users sign in to view their profile. + </Trans> + ) : ( + <> + <Trans>This {screenDescription} has been flagged:</Trans> + <Text style={[a.text_lg, a.font_semibold, t.atoms.text, a.ml_xs]}> + {desc.name}.{' '} + </Text> + <TouchableWithoutFeedback + onPress={() => { + control.open() + }} + accessibilityRole="button" + accessibilityLabel={_(msg`Learn more about this warning`)} + accessibilityHint=""> + <Text style={[a.text_lg, {color: t.palette.primary_500}]}> + <Trans>Learn More</Trans> + </Text> + </TouchableWithoutFeedback> + + <ModerationDetailsDialog control={control} modcause={blur} /> + </> + )}{' '} + </Text> + {isMobile && <View style={a.flex_1} />} + <View style={[a.flex_row, a.justify_center, a.my_md, a.gap_md]}> + <Button + variant="solid" + color="primary" + size="large" + style={[a.rounded_full]} + label={_(msg`Go back`)} + onPress={() => { + if (navigation.canGoBack()) { + navigation.goBack() + } else { + navigation.navigate('Home') + } + }}> + <ButtonText> + <Trans>Go back</Trans> + </ButtonText> + </Button> + {!modui.noOverride && ( + <Button + variant="solid" + color="secondary" + size="large" + style={[a.rounded_full]} + label={_(msg`Show anyway`)} + onPress={() => setOverride(v => !v)}> + <ButtonText> + <Trans>Show anyway</Trans> + </ButtonText> + </Button> + )} + </View> + </CenteredView> + ) +} diff --git a/src/lib/__tests__/moderatePost_wrapped.test.ts b/src/lib/__tests__/moderatePost_wrapped.test.ts deleted file mode 100644 index 45566281a..000000000 --- a/src/lib/__tests__/moderatePost_wrapped.test.ts +++ /dev/null @@ -1,692 +0,0 @@ -import {describe, it, expect} from '@jest/globals' -import {RichText} from '@atproto/api' - -import {hasMutedWord} from '../moderatePost_wrapped' - -describe(`hasMutedWord`, () => { - describe(`tags`, () => { - it(`match: outline tag`, () => { - const rt = new RichText({ - text: `This is a post #inlineTag`, - }) - rt.detectFacetsWithoutResolution() - - const match = hasMutedWord({ - mutedWords: [{value: 'outlineTag', targets: ['tag']}], - text: rt.text, - facets: rt.facets, - outlineTags: ['outlineTag'], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - - it(`match: inline tag`, () => { - const rt = new RichText({ - text: `This is a post #inlineTag`, - }) - rt.detectFacetsWithoutResolution() - - const match = hasMutedWord({ - mutedWords: [{value: 'inlineTag', targets: ['tag']}], - text: rt.text, - facets: rt.facets, - outlineTags: ['outlineTag'], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - - it(`match: content target matches inline tag`, () => { - const rt = new RichText({ - text: `This is a post #inlineTag`, - }) - rt.detectFacetsWithoutResolution() - - const match = hasMutedWord({ - mutedWords: [{value: 'inlineTag', targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: ['outlineTag'], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - - it(`no match: only tag targets`, () => { - const rt = new RichText({ - text: `This is a post`, - }) - rt.detectFacetsWithoutResolution() - - const match = hasMutedWord({ - mutedWords: [{value: 'inlineTag', targets: ['tag']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(false) - }) - }) - - describe(`early exits`, () => { - it(`match: single character 希`, () => { - /** - * @see https://bsky.app/profile/mukuuji.bsky.social/post/3klji4fvsdk2c - */ - const rt = new RichText({ - text: `改善希望ã§ã™`, - }) - rt.detectFacetsWithoutResolution() - - const match = hasMutedWord({ - mutedWords: [{value: '希', targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - - it(`no match: long muted word, short post`, () => { - const rt = new RichText({ - text: `hey`, - }) - rt.detectFacetsWithoutResolution() - - const match = hasMutedWord({ - mutedWords: [{value: 'politics', targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(false) - }) - - it(`match: exact text`, () => { - const rt = new RichText({ - text: `javascript`, - }) - rt.detectFacetsWithoutResolution() - - const match = hasMutedWord({ - mutedWords: [{value: 'javascript', targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - }) - - describe(`general content`, () => { - it(`match: word within post`, () => { - const rt = new RichText({ - text: `This is a post about javascript`, - }) - rt.detectFacetsWithoutResolution() - - const match = hasMutedWord({ - mutedWords: [{value: 'javascript', targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - - it(`no match: partial word`, () => { - const rt = new RichText({ - text: `Use your brain, Eric`, - }) - rt.detectFacetsWithoutResolution() - - const match = hasMutedWord({ - mutedWords: [{value: 'ai', targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(false) - }) - - it(`match: multiline`, () => { - const rt = new RichText({ - text: `Use your\n\tbrain, Eric`, - }) - rt.detectFacetsWithoutResolution() - - const match = hasMutedWord({ - mutedWords: [{value: 'brain', targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - - it(`match: :)`, () => { - const rt = new RichText({ - text: `So happy :)`, - }) - rt.detectFacetsWithoutResolution() - - const match = hasMutedWord({ - mutedWords: [{value: `:)`, targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - }) - - describe(`punctuation semi-fuzzy`, () => { - describe(`yay!`, () => { - const rt = new RichText({ - text: `We're federating, yay!`, - }) - rt.detectFacetsWithoutResolution() - - it(`match: yay!`, () => { - const match = hasMutedWord({ - mutedWords: [{value: 'yay!', targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - - it(`match: yay`, () => { - const match = hasMutedWord({ - mutedWords: [{value: 'yay', targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - }) - - describe(`y!ppee!!`, () => { - const rt = new RichText({ - text: `We're federating, y!ppee!!`, - }) - rt.detectFacetsWithoutResolution() - - it(`match: y!ppee`, () => { - const match = hasMutedWord({ - mutedWords: [{value: 'y!ppee', targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - - // single exclamation point, source has double - it(`no match: y!ppee!`, () => { - const match = hasMutedWord({ - mutedWords: [{value: 'y!ppee!', targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - }) - - describe(`Why so S@assy?`, () => { - const rt = new RichText({ - text: `Why so S@assy?`, - }) - rt.detectFacetsWithoutResolution() - - it(`match: S@assy`, () => { - const match = hasMutedWord({ - mutedWords: [{value: 'S@assy', targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - - it(`match: s@assy`, () => { - const match = hasMutedWord({ - mutedWords: [{value: 's@assy', targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - }) - - describe(`New York Times`, () => { - const rt = new RichText({ - text: `New York Times`, - }) - rt.detectFacetsWithoutResolution() - - // case insensitive - it(`match: new york times`, () => { - const match = hasMutedWord({ - mutedWords: [{value: 'new york times', targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - }) - - describe(`!command`, () => { - const rt = new RichText({ - text: `Idk maybe a bot !command`, - }) - rt.detectFacetsWithoutResolution() - - it(`match: !command`, () => { - const match = hasMutedWord({ - mutedWords: [{value: `!command`, targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - - it(`match: command`, () => { - const match = hasMutedWord({ - mutedWords: [{value: `command`, targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - - it(`no match: !command`, () => { - const rt = new RichText({ - text: `Idk maybe a bot command`, - }) - rt.detectFacetsWithoutResolution() - - const match = hasMutedWord({ - mutedWords: [{value: `!command`, targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(false) - }) - }) - - describe(`e/acc`, () => { - const rt = new RichText({ - text: `I'm e/acc pilled`, - }) - rt.detectFacetsWithoutResolution() - - it(`match: e/acc`, () => { - const match = hasMutedWord({ - mutedWords: [{value: `e/acc`, targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - - it(`match: acc`, () => { - const match = hasMutedWord({ - mutedWords: [{value: `acc`, targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - }) - - describe(`super-bad`, () => { - const rt = new RichText({ - text: `I'm super-bad`, - }) - rt.detectFacetsWithoutResolution() - - it(`match: super-bad`, () => { - const match = hasMutedWord({ - mutedWords: [{value: `super-bad`, targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - - it(`match: super`, () => { - const match = hasMutedWord({ - mutedWords: [{value: `super`, targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - - it(`match: super bad`, () => { - const match = hasMutedWord({ - mutedWords: [{value: `super bad`, targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - - it(`match: superbad`, () => { - const match = hasMutedWord({ - mutedWords: [{value: `superbad`, targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(false) - }) - }) - - describe(`idk_what_this_would_be`, () => { - const rt = new RichText({ - text: `Weird post with idk_what_this_would_be`, - }) - rt.detectFacetsWithoutResolution() - - it(`match: idk what this would be`, () => { - const match = hasMutedWord({ - mutedWords: [{value: `idk what this would be`, targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - - it(`no match: idk what this would be for`, () => { - // extra word - const match = hasMutedWord({ - mutedWords: [ - {value: `idk what this would be for`, targets: ['content']}, - ], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(false) - }) - - it(`match: idk`, () => { - // extra word - const match = hasMutedWord({ - mutedWords: [{value: `idk`, targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - - it(`match: idkwhatthiswouldbe`, () => { - const match = hasMutedWord({ - mutedWords: [{value: `idkwhatthiswouldbe`, targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(false) - }) - }) - - describe(`parentheses`, () => { - const rt = new RichText({ - text: `Post with context(iykyk)`, - }) - rt.detectFacetsWithoutResolution() - - it(`match: context(iykyk)`, () => { - const match = hasMutedWord({ - mutedWords: [{value: `context(iykyk)`, targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - - it(`match: context`, () => { - const match = hasMutedWord({ - mutedWords: [{value: `context`, targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - - it(`match: iykyk`, () => { - const match = hasMutedWord({ - mutedWords: [{value: `iykyk`, targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - - it(`match: (iykyk)`, () => { - const match = hasMutedWord({ - mutedWords: [{value: `(iykyk)`, targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - }) - - describe(`🦋`, () => { - const rt = new RichText({ - text: `Post with 🦋`, - }) - rt.detectFacetsWithoutResolution() - - it(`match: 🦋`, () => { - const match = hasMutedWord({ - mutedWords: [{value: `🦋`, targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - }) - }) - - describe(`phrases`, () => { - describe(`I like turtles, or how I learned to stop worrying and love the internet.`, () => { - const rt = new RichText({ - text: `I like turtles, or how I learned to stop worrying and love the internet.`, - }) - rt.detectFacetsWithoutResolution() - - it(`match: stop worrying`, () => { - const match = hasMutedWord({ - mutedWords: [{value: 'stop worrying', targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - - it(`match: turtles, or how`, () => { - const match = hasMutedWord({ - mutedWords: [{value: 'turtles, or how', targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - }) - }) - - describe(`languages without spaces`, () => { - // I love turtles, or how I learned to stop worrying and love the internet - describe(`ç§ã¯ã‚«ãƒ¡ãŒå¥½ãã§ã™ã€ã¾ãŸã¯ã©ã®ã‚ˆã†ã«ã—ã¦å¿ƒé…ã™ã‚‹ã®ã‚’ã‚„ã‚ã¦ã‚¤ãƒ³ã‚¿ãƒ¼ãƒãƒƒãƒˆã‚’æ„›ã™ã‚‹ã‚ˆã†ã«ãªã£ãŸã®ã‹`, () => { - const rt = new RichText({ - text: `ç§ã¯ã‚«ãƒ¡ãŒå¥½ãã§ã™ã€ã¾ãŸã¯ã©ã®ã‚ˆã†ã«ã—ã¦å¿ƒé…ã™ã‚‹ã®ã‚’ã‚„ã‚ã¦ã‚¤ãƒ³ã‚¿ãƒ¼ãƒãƒƒãƒˆã‚’æ„›ã™ã‚‹ã‚ˆã†ã«ãªã£ãŸã®ã‹`, - }) - rt.detectFacetsWithoutResolution() - - // internet - it(`match: インターãƒãƒƒãƒˆ`, () => { - const match = hasMutedWord({ - mutedWords: [{value: 'インターãƒãƒƒãƒˆ', targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - languages: ['ja'], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - }) - }) - - describe(`doesn't mute own post`, () => { - it(`does mute if it isn't own post`, () => { - const rt = new RichText({ - text: `Mute words!`, - }) - - const match = hasMutedWord({ - mutedWords: [{value: 'words', targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: false, - }) - - expect(match).toBe(true) - }) - - it(`doesn't mute own post when muted word is in text`, () => { - const rt = new RichText({ - text: `Mute words!`, - }) - - const match = hasMutedWord({ - mutedWords: [{value: 'words', targets: ['content']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: true, - }) - - expect(match).toBe(false) - }) - - it(`doesn't mute own post when muted word is in tags`, () => { - const rt = new RichText({ - text: `Mute #words!`, - }) - - const match = hasMutedWord({ - mutedWords: [{value: 'words', targets: ['tags']}], - text: rt.text, - facets: rt.facets, - outlineTags: [], - isOwnPost: true, - }) - - expect(match).toBe(false) - }) - }) -}) diff --git a/src/lib/constants.ts b/src/lib/constants.ts index e86844395..f5a72669a 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -35,6 +35,10 @@ export const MAX_GRAPHEME_LENGTH = 300 // but increasing limit per user feedback export const MAX_ALT_TEXT = 1000 +export function IS_TEST_USER(handle?: string) { + return handle && handle?.endsWith('.test') +} + export function IS_PROD_SERVICE(url?: string) { return url && url !== STAGING_SERVICE && url !== LOCAL_DEV_SERVICE } diff --git a/src/lib/hooks/useDedupe.ts b/src/lib/hooks/useDedupe.ts new file mode 100644 index 000000000..d9432cb2c --- /dev/null +++ b/src/lib/hooks/useDedupe.ts @@ -0,0 +1,17 @@ +import React from 'react' + +export const useDedupe = () => { + const canDo = React.useRef(true) + + return React.useRef((cb: () => unknown) => { + if (canDo.current) { + canDo.current = false + setTimeout(() => { + canDo.current = true + }, 250) + cb() + return true + } + return false + }).current +} diff --git a/src/lib/hooks/useNavigationDeduped.ts b/src/lib/hooks/useNavigationDeduped.ts new file mode 100644 index 000000000..d913f7f3d --- /dev/null +++ b/src/lib/hooks/useNavigationDeduped.ts @@ -0,0 +1,80 @@ +import React from 'react' +import {useNavigation} from '@react-navigation/core' +import {AllNavigatorParams, NavigationProp} from 'lib/routes/types' +import type {NavigationAction} from '@react-navigation/routers' +import {NavigationState} from '@react-navigation/native' +import {useDedupe} from 'lib/hooks/useDedupe' + +export type DebouncedNavigationProp = Pick< + NavigationProp, + | 'popToTop' + | 'push' + | 'navigate' + | 'canGoBack' + | 'replace' + | 'dispatch' + | 'goBack' + | 'getState' +> + +export function useNavigationDeduped() { + const navigation = useNavigation<NavigationProp>() + const dedupe = useDedupe() + + return React.useMemo( + (): DebouncedNavigationProp => ({ + // Types from @react-navigation/routers/lib/typescript/src/StackRouter.ts + push: <RouteName extends keyof AllNavigatorParams>( + ...args: undefined extends AllNavigatorParams[RouteName] + ? + | [screen: RouteName] + | [screen: RouteName, params: AllNavigatorParams[RouteName]] + : [screen: RouteName, params: AllNavigatorParams[RouteName]] + ) => { + dedupe(() => navigation.push(...args)) + }, + // Types from @react-navigation/core/src/types.tsx + navigate: <RouteName extends keyof AllNavigatorParams>( + ...args: RouteName extends unknown + ? undefined extends AllNavigatorParams[RouteName] + ? + | [screen: RouteName] + | [screen: RouteName, params: AllNavigatorParams[RouteName]] + : [screen: RouteName, params: AllNavigatorParams[RouteName]] + : never + ) => { + dedupe(() => navigation.navigate(...args)) + }, + // Types from @react-navigation/routers/lib/typescript/src/StackRouter.ts + replace: <RouteName extends keyof AllNavigatorParams>( + ...args: undefined extends AllNavigatorParams[RouteName] + ? + | [screen: RouteName] + | [screen: RouteName, params: AllNavigatorParams[RouteName]] + : [screen: RouteName, params: AllNavigatorParams[RouteName]] + ) => { + dedupe(() => navigation.replace(...args)) + }, + dispatch: ( + action: + | NavigationAction + | ((state: NavigationState) => NavigationAction), + ) => { + dedupe(() => navigation.dispatch(action)) + }, + popToTop: () => { + dedupe(() => navigation.popToTop()) + }, + goBack: () => { + dedupe(() => navigation.goBack()) + }, + canGoBack: () => { + return navigation.canGoBack() + }, + getState: () => { + return navigation.getState() + }, + }), + [dedupe, navigation], + ) +} diff --git a/src/lib/hooks/useOTAUpdate.ts b/src/lib/hooks/useOTAUpdate.ts index 53eab300e..d35179256 100644 --- a/src/lib/hooks/useOTAUpdate.ts +++ b/src/lib/hooks/useOTAUpdate.ts @@ -2,25 +2,9 @@ import * as Updates from 'expo-updates' import {useCallback, useEffect} from 'react' import {AppState} from 'react-native' import {logger} from '#/logger' -import {useModalControls} from '#/state/modals' -import {t} from '@lingui/macro' export function useOTAUpdate() { - const {openModal} = useModalControls() - // HELPER FUNCTIONS - const showUpdatePopup = useCallback(() => { - openModal({ - name: 'confirm', - title: t`Update Available`, - message: t`A new version of the app is available. Please update to continue using the app.`, - onPressConfirm: async () => { - Updates.reloadAsync().catch(err => { - throw err - }) - }, - }) - }, [openModal]) const checkForUpdate = useCallback(async () => { logger.debug('useOTAUpdate: Checking for update...') try { @@ -32,32 +16,26 @@ export function useOTAUpdate() { } // Otherwise fetch the update in the background, so even if the user rejects switching to latest version it will be done automatically on next relaunch. await Updates.fetchUpdateAsync() - // show a popup modal - showUpdatePopup() } catch (e) { logger.error('useOTAUpdate: Error while checking for update', { message: e, }) } - }, [showUpdatePopup]) - const updateEventListener = useCallback( - (event: Updates.UpdateEvent) => { - logger.debug('useOTAUpdate: Listening for update...') - if (event.type === Updates.UpdateEventType.ERROR) { - logger.error('useOTAUpdate: Error while listening for update', { - message: event.message, - }) - } else if (event.type === Updates.UpdateEventType.NO_UPDATE_AVAILABLE) { - // Handle no update available - // do nothing - } else if (event.type === Updates.UpdateEventType.UPDATE_AVAILABLE) { - // Handle update available - // open modal, ask for user confirmation, and reload the app - showUpdatePopup() - } - }, - [showUpdatePopup], - ) + }, []) + const updateEventListener = useCallback((event: Updates.UpdateEvent) => { + logger.debug('useOTAUpdate: Listening for update...') + if (event.type === Updates.UpdateEventType.ERROR) { + logger.error('useOTAUpdate: Error while listening for update', { + message: event.message, + }) + } else if (event.type === Updates.UpdateEventType.NO_UPDATE_AVAILABLE) { + // Handle no update available + // do nothing + } else if (event.type === Updates.UpdateEventType.UPDATE_AVAILABLE) { + // Handle update available + // open modal, ask for user confirmation, and reload the app + } + }, []) useEffect(() => { // ADD EVENT LISTENERS diff --git a/src/lib/media/picker.shared.ts b/src/lib/media/picker.shared.ts index 8bade34e2..96e82e4c7 100644 --- a/src/lib/media/picker.shared.ts +++ b/src/lib/media/picker.shared.ts @@ -18,11 +18,18 @@ export async function openPicker(opts?: ImagePickerOptions) { Toast.show('You may only select up to 4 images') } - return (response.assets ?? []).slice(0, 4).map(image => ({ - mime: 'image/jpeg', - height: image.height, - width: image.width, - path: image.uri, - size: getDataUriSize(image.uri), - })) + return (response.assets ?? []) + .slice(0, 4) + .filter(asset => { + if (asset.mimeType?.startsWith('image/')) return true + Toast.show('Only image files are supported') + return false + }) + .map(image => ({ + mime: 'image/jpeg', + height: image.height, + width: image.width, + path: image.uri, + size: getDataUriSize(image.uri), + })) } diff --git a/src/lib/moderatePost_wrapped.ts b/src/lib/moderatePost_wrapped.ts index 9f6fa9c07..0ce01368a 100644 --- a/src/lib/moderatePost_wrapped.ts +++ b/src/lib/moderatePost_wrapped.ts @@ -1,380 +1,30 @@ -import { - AppBskyEmbedRecord, - AppBskyEmbedRecordWithMedia, - moderatePost, - AppBskyActorDefs, - AppBskyFeedPost, - AppBskyRichtextFacet, - AppBskyEmbedImages, - AppBskyEmbedExternal, -} from '@atproto/api' +import {moderatePost, BSKY_LABELER_DID} from '@atproto/api' type ModeratePost = typeof moderatePost -type Options = Parameters<ModeratePost>[1] & { - hiddenPosts?: string[] - mutedWords?: AppBskyActorDefs.MutedWord[] -} - -const REGEX = { - LEADING_TRAILING_PUNCTUATION: /(?:^\p{P}+|\p{P}+$)/gu, - ESCAPE: /[[\]{}()*+?.\\^$|\s]/g, - SEPARATORS: /[\/\-\–\—\(\)\[\]\_]+/g, - WORD_BOUNDARY: /[\s\n\t\r\f\v]+?/g, -} - -/** - * List of 2-letter lang codes for languages that either don't use spaces, or - * don't use spaces in a way conducive to word-based filtering. - * - * For these, we use a simple `String.includes` to check for a match. - */ -const LANGUAGE_EXCEPTIONS = [ - 'ja', // Japanese - 'zh', // Chinese - 'ko', // Korean - 'th', // Thai - 'vi', // Vietnamese -] - -export function hasMutedWord({ - mutedWords, - text, - facets, - outlineTags, - languages, - isOwnPost, -}: { - mutedWords: AppBskyActorDefs.MutedWord[] - text: string - facets?: AppBskyRichtextFacet.Main[] - outlineTags?: string[] - languages?: string[] - isOwnPost: boolean -}) { - if (isOwnPost) return false - - const exception = LANGUAGE_EXCEPTIONS.includes(languages?.[0] || '') - const tags = ([] as string[]) - .concat(outlineTags || []) - .concat( - facets - ?.filter(facet => { - return facet.features.find(feature => - AppBskyRichtextFacet.isTag(feature), - ) - }) - .map(t => t.features[0].tag as string) || [], - ) - .map(t => t.toLowerCase()) - - for (const mute of mutedWords) { - const mutedWord = mute.value.toLowerCase() - const postText = text.toLowerCase() - - // `content` applies to tags as well - if (tags.includes(mutedWord)) return true - // rest of the checks are for `content` only - if (!mute.targets.includes('content')) continue - // single character or other exception, has to use includes - if ((mutedWord.length === 1 || exception) && postText.includes(mutedWord)) - return true - // too long - if (mutedWord.length > postText.length) continue - // exact match - if (mutedWord === postText) return true - // any muted phrase with space or punctuation - if (/(?:\s|\p{P})+?/u.test(mutedWord) && postText.includes(mutedWord)) - return true - - // check individual character groups - const words = postText.split(REGEX.WORD_BOUNDARY) - for (const word of words) { - if (word === mutedWord) return true - - // compare word without leading/trailing punctuation, but allow internal - // punctuation (such as `s@ssy`) - const wordTrimmedPunctuation = word.replace( - REGEX.LEADING_TRAILING_PUNCTUATION, - '', - ) - - if (mutedWord === wordTrimmedPunctuation) return true - if (mutedWord.length > wordTrimmedPunctuation.length) continue - - // handle hyphenated, slash separated words, etc - if (REGEX.SEPARATORS.test(wordTrimmedPunctuation)) { - // check against full normalized phrase - const wordNormalizedSeparators = wordTrimmedPunctuation.replace( - REGEX.SEPARATORS, - ' ', - ) - const mutedWordNormalizedSeparators = mutedWord.replace( - REGEX.SEPARATORS, - ' ', - ) - // hyphenated (or other sep) to spaced words - if (wordNormalizedSeparators === mutedWordNormalizedSeparators) - return true - - /* Disabled for now e.g. `super-cool` to `supercool` - const wordNormalizedCompressed = wordNormalizedSeparators.replace( - REGEX.WORD_BOUNDARY, - '', - ) - const mutedWordNormalizedCompressed = - mutedWordNormalizedSeparators.replace(/\s+?/g, '') - // hyphenated (or other sep) to non-hyphenated contiguous word - if (mutedWordNormalizedCompressed === wordNormalizedCompressed) - return true - */ - - // then individual parts of separated phrases/words - const wordParts = wordTrimmedPunctuation.split(REGEX.SEPARATORS) - for (const wp of wordParts) { - // still retain internal punctuation - if (wp === mutedWord) return true - } - } - } - } - - return false -} +type Options = Parameters<ModeratePost>[1] export function moderatePost_wrapped( subject: Parameters<ModeratePost>[0], opts: Options, ) { - const {hiddenPosts = [], mutedWords = [], ...options} = opts - const moderations = moderatePost(subject, options) - const isOwnPost = subject.author.did === opts.userDid - - if (hiddenPosts.includes(subject.uri)) { - moderations.content.filter = true - moderations.content.blur = true - if (!moderations.content.cause) { - moderations.content.cause = { - // @ts-ignore Temporary extension to the moderation system -prf - type: 'post-hidden', - source: {type: 'user'}, - priority: 1, - } - } - } + // HACK + // temporarily translate 'gore' into 'graphic-media' during the transition period + // can remove this in a few months + // -prf + translateOldLabels(subject) - if (AppBskyFeedPost.isRecord(subject.record)) { - let muted = hasMutedWord({ - mutedWords, - text: subject.record.text, - facets: subject.record.facets || [], - outlineTags: subject.record.tags || [], - languages: subject.record.langs, - isOwnPost, - }) - - if ( - subject.record.embed && - AppBskyEmbedImages.isMain(subject.record.embed) - ) { - for (const image of subject.record.embed.images) { - muted = - muted || - hasMutedWord({ - mutedWords, - text: image.alt, - facets: [], - outlineTags: [], - languages: subject.record.langs, - isOwnPost, - }) - } - } - - if (muted) { - moderations.content.filter = true - moderations.content.blur = true - if (!moderations.content.cause) { - moderations.content.cause = { - // @ts-ignore Temporary extension to the moderation system -prf - type: 'muted-word', - source: {type: 'user'}, - priority: 1, - } - } - } - } - - if (subject.embed) { - let embedHidden = false - let embedMuted = false - let externalMuted = false - - if (AppBskyEmbedRecord.isViewRecord(subject.embed.record)) { - embedHidden = hiddenPosts.includes(subject.embed.record.uri) - } - if ( - AppBskyEmbedRecordWithMedia.isView(subject.embed) && - AppBskyEmbedRecord.isViewRecord(subject.embed.record.record) - ) { - embedHidden = hiddenPosts.includes(subject.embed.record.record.uri) - } - - if (AppBskyEmbedRecord.isViewRecord(subject.embed.record)) { - if (AppBskyFeedPost.isRecord(subject.embed.record.value)) { - const embeddedPost = subject.embed.record.value - - embedMuted = - embedMuted || - hasMutedWord({ - mutedWords, - text: embeddedPost.text, - facets: embeddedPost.facets, - outlineTags: embeddedPost.tags, - languages: embeddedPost.langs, - isOwnPost, - }) - - if (AppBskyEmbedImages.isMain(embeddedPost.embed)) { - for (const image of embeddedPost.embed.images) { - embedMuted = - embedMuted || - hasMutedWord({ - mutedWords, - text: image.alt, - facets: [], - outlineTags: [], - languages: embeddedPost.langs, - isOwnPost, - }) - } - } - - if (AppBskyEmbedExternal.isMain(embeddedPost.embed)) { - const {external} = embeddedPost.embed - - embedMuted = - embedMuted || - hasMutedWord({ - mutedWords, - text: external.title + ' ' + external.description, - facets: [], - outlineTags: [], - languages: [], - isOwnPost, - }) - } - - if (AppBskyEmbedRecordWithMedia.isMain(embeddedPost.embed)) { - if (AppBskyEmbedExternal.isMain(embeddedPost.embed.media)) { - const {external} = embeddedPost.embed.media - - embedMuted = - embedMuted || - hasMutedWord({ - mutedWords, - text: external.title + ' ' + external.description, - facets: [], - outlineTags: [], - languages: [], - isOwnPost, - }) - } - - if (AppBskyEmbedImages.isMain(embeddedPost.embed.media)) { - for (const image of embeddedPost.embed.media.images) { - embedMuted = - embedMuted || - hasMutedWord({ - mutedWords, - text: image.alt, - facets: [], - outlineTags: [], - languages: AppBskyFeedPost.isRecord(embeddedPost.record) - ? embeddedPost.langs - : [], - isOwnPost, - }) - } - } - } - } - } - - if (AppBskyEmbedExternal.isView(subject.embed)) { - const {external} = subject.embed - - externalMuted = - externalMuted || - hasMutedWord({ - mutedWords, - text: external.title + ' ' + external.description, - facets: [], - outlineTags: [], - languages: [], - isOwnPost, - }) - } - - if ( - AppBskyEmbedRecordWithMedia.isView(subject.embed) && - AppBskyEmbedRecord.isViewRecord(subject.embed.record.record) - ) { - if (AppBskyFeedPost.isRecord(subject.embed.record.record.value)) { - const post = subject.embed.record.record.value - embedMuted = - embedMuted || - hasMutedWord({ - mutedWords, - text: post.text, - facets: post.facets, - outlineTags: post.tags, - languages: post.langs, - isOwnPost, - }) - } - - if (AppBskyEmbedImages.isView(subject.embed.media)) { - for (const image of subject.embed.media.images) { - embedMuted = - embedMuted || - hasMutedWord({ - mutedWords, - text: image.alt, - facets: [], - outlineTags: [], - languages: AppBskyFeedPost.isRecord(subject.record) - ? subject.record.langs - : [], - isOwnPost, - }) - } - } - } + return moderatePost(subject, opts) +} - if (embedHidden) { - moderations.embed.filter = true - moderations.embed.blur = true - if (!moderations.embed.cause) { - moderations.embed.cause = { - // @ts-ignore Temporary extension to the moderation system -prf - type: 'post-hidden', - source: {type: 'user'}, - priority: 1, - } - } - } else if (externalMuted || embedMuted) { - moderations.content.filter = true - moderations.content.blur = true - if (!moderations.content.cause) { - moderations.content.cause = { - // @ts-ignore Temporary extension to the moderation system -prf - type: 'muted-word', - source: {type: 'user'}, - priority: 1, - } +function translateOldLabels(subject: Parameters<ModeratePost>[0]) { + if (subject.labels) { + for (const label of subject.labels) { + if ( + label.val === 'gore' && + (!label.src || label.src === BSKY_LABELER_DID) + ) { + label.val = 'graphic-media' } } } - - return moderations } diff --git a/src/lib/moderation.ts b/src/lib/moderation.ts index b6ebb47a0..4105c2c2d 100644 --- a/src/lib/moderation.ts +++ b/src/lib/moderation.ts @@ -1,149 +1,81 @@ -import {ModerationCause, ProfileModeration, PostModeration} from '@atproto/api' +import { + ModerationCause, + ModerationUI, + InterpretedLabelValueDefinition, + LABELS, + AppBskyLabelerDefs, + BskyAgent, + ModerationOpts, +} from '@atproto/api' -export interface ModerationCauseDescription { - name: string - description: string -} +import {sanitizeDisplayName} from '#/lib/strings/display-names' +import {sanitizeHandle} from '#/lib/strings/handles' -export function describeModerationCause( - cause: ModerationCause | undefined, - context: 'account' | 'content', -): ModerationCauseDescription { - if (!cause) { - return { - name: 'Content Warning', - description: - 'Moderator has chosen to set a general warning on the content.', - } - } - if (cause.type === 'blocking') { - if (cause.source.type === 'list') { - return { - name: `User Blocked by "${cause.source.list.name}"`, - description: - 'You have blocked this user. You cannot view their content.', - } - } else { - return { - name: 'User Blocked', - description: - 'You have blocked this user. You cannot view their content.', - } - } - } - if (cause.type === 'blocked-by') { - return { - name: 'User Blocking You', - description: 'This user has blocked you. You cannot view their content.', - } - } - if (cause.type === 'block-other') { - return { - name: 'Content Not Available', - description: - 'This content is not available because one of the users involved has blocked the other.', - } - } - if (cause.type === 'muted') { - if (cause.source.type === 'list') { - return { - name: - context === 'account' - ? `Muted by "${cause.source.list.name}"` - : `Post by muted user ("${cause.source.list.name}")`, - description: 'You have muted this user', - } - } else { - return { - name: context === 'account' ? 'Muted User' : 'Post by muted user', - description: 'You have muted this user', - } - } - } - // @ts-ignore Temporary extension to the moderation system -prf - if (cause.type === 'post-hidden') { - return { - name: 'Post Hidden by You', - description: 'You have hidden this post', - } - } - // @ts-ignore Temporary extension to the moderation system -prf - if (cause.type === 'muted-word') { - return { - name: 'Post hidden by muted word', - description: `You've chosen to hide a word or tag within this post.`, - } +export function getModerationCauseKey(cause: ModerationCause): string { + const source = + cause.source.type === 'labeler' + ? cause.source.did + : cause.source.type === 'list' + ? cause.source.list.uri + : 'user' + if (cause.type === 'label') { + return `label:${cause.label.val}:${source}` } - return cause.labelDef.strings[context].en + return `${cause.type}:${source}` } -export function getProfileModerationCauses( - moderation: ProfileModeration, -): ModerationCause[] { - /* - Gather everything on profile and account that blurs or alerts - */ - return [ - moderation.decisions.profile.cause, - ...moderation.decisions.profile.additionalCauses, - moderation.decisions.account.cause, - ...moderation.decisions.account.additionalCauses, - ].filter(cause => { - if (!cause) { - return false - } - if (cause?.type === 'label') { - if ( - cause.labelDef.onwarn === 'blur' || - cause.labelDef.onwarn === 'alert' - ) { - return true - } else { - return false - } - } - return true - }) as ModerationCause[] +export function isJustAMute(modui: ModerationUI): boolean { + return modui.filters.length === 1 && modui.filters[0].type === 'muted' } -export function isPostMediaBlurred( - decisions: PostModeration['decisions'], -): boolean { - return decisions.post.blurMedia +export function getLabelingServiceTitle({ + displayName, + handle, +}: { + displayName?: string + handle: string +}) { + return displayName + ? sanitizeDisplayName(displayName) + : sanitizeHandle(handle, '@') } -export function isQuoteBlurred( - decisions: PostModeration['decisions'], -): boolean { - return ( - decisions.quote?.blur || - decisions.quote?.blurMedia || - decisions.quote?.filter || - decisions.quotedAccount?.blur || - decisions.quotedAccount?.filter || - false - ) +export function lookupLabelValueDefinition( + labelValue: string, + customDefs: InterpretedLabelValueDefinition[] | undefined, +): InterpretedLabelValueDefinition | undefined { + let def + if (!labelValue.startsWith('!') && customDefs) { + def = customDefs.find(d => d.identifier === labelValue) + } + if (!def) { + def = LABELS[labelValue as keyof typeof LABELS] + } + return def } -export function isCauseALabelOnUri( - cause: ModerationCause | undefined, - uri: string, +export function isAppLabeler( + labeler: + | string + | AppBskyLabelerDefs.LabelerView + | AppBskyLabelerDefs.LabelerViewDetailed, ): boolean { - if (cause?.type !== 'label') { - return false + if (typeof labeler === 'string') { + return BskyAgent.appLabelers.includes(labeler) } - return cause.label.uri === uri + return BskyAgent.appLabelers.includes(labeler.creator.did) } -export function getModerationCauseKey(cause: ModerationCause): string { - const source = - cause.source.type === 'labeler' - ? cause.source.labeler.did - : cause.source.type === 'list' - ? cause.source.list.uri - : 'user' - if (cause.type === 'label') { - return `label:${cause.label.val}:${source}` +export function isLabelerSubscribed( + labeler: + | string + | AppBskyLabelerDefs.LabelerView + | AppBskyLabelerDefs.LabelerViewDetailed, + modOpts: ModerationOpts, +) { + labeler = typeof labeler === 'string' ? labeler : labeler.creator.did + if (isAppLabeler(labeler)) { + return true } - return `${cause.type}:${source}` + return modOpts.prefs.labelers.find(l => l.did === labeler) } diff --git a/src/lib/moderation/useGlobalLabelStrings.ts b/src/lib/moderation/useGlobalLabelStrings.ts new file mode 100644 index 000000000..1c5a48231 --- /dev/null +++ b/src/lib/moderation/useGlobalLabelStrings.ts @@ -0,0 +1,52 @@ +import {msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {useMemo} from 'react' + +export type GlobalLabelStrings = Record< + string, + { + name: string + description: string + } +> + +export function useGlobalLabelStrings(): GlobalLabelStrings { + const {_} = useLingui() + return useMemo( + () => ({ + '!hide': { + name: _(msg`Content Blocked`), + description: _(msg`This content has been hidden by the moderators.`), + }, + '!warn': { + name: _(msg`Content Warning`), + description: _( + msg`This content has received a general warning from moderators.`, + ), + }, + '!no-unauthenticated': { + name: _(msg`Sign-in Required`), + description: _( + msg`This user has requested that their content only be shown to signed-in users.`, + ), + }, + porn: { + name: _(msg`Pornography`), + description: _(msg`Explicit sexual images.`), + }, + sexual: { + name: _(msg`Sexually Suggestive`), + description: _(msg`Does not include nudity.`), + }, + nudity: { + name: _(msg`Non-sexual Nudity`), + description: _(msg`E.g. artistic nudes.`), + }, + 'graphic-media': { + name: _(msg`Graphic Media`), + description: _(msg`Explicit or potentially disturbing media.`), + }, + }), + [_], + ) +} diff --git a/src/lib/moderation/useLabelBehaviorDescription.ts b/src/lib/moderation/useLabelBehaviorDescription.ts new file mode 100644 index 000000000..0250c1bc8 --- /dev/null +++ b/src/lib/moderation/useLabelBehaviorDescription.ts @@ -0,0 +1,70 @@ +import {InterpretedLabelValueDefinition, LabelPreference} from '@atproto/api' +import {useLingui} from '@lingui/react' +import {msg} from '@lingui/macro' + +export function useLabelBehaviorDescription( + labelValueDef: InterpretedLabelValueDefinition, + pref: LabelPreference, +) { + const {_} = useLingui() + if (pref === 'ignore') { + return _(msg`Off`) + } + if (labelValueDef.blurs === 'content' || labelValueDef.blurs === 'media') { + if (pref === 'hide') { + return _(msg`Hide`) + } + return _(msg`Warn`) + } else if (labelValueDef.severity === 'alert') { + if (pref === 'hide') { + return _(msg`Hide`) + } + return _(msg`Warn`) + } else if (labelValueDef.severity === 'inform') { + if (pref === 'hide') { + return _(msg`Hide`) + } + return _(msg`Show badge`) + } else { + if (pref === 'hide') { + return _(msg`Hide`) + } + return _(msg`Disabled`) + } +} + +export function useLabelLongBehaviorDescription( + labelValueDef: InterpretedLabelValueDefinition, + pref: LabelPreference, +) { + const {_} = useLingui() + if (pref === 'ignore') { + return _(msg`Disabled`) + } + if (labelValueDef.blurs === 'content') { + if (pref === 'hide') { + return _(msg`Warn content and filter from feeds`) + } + return _(msg`Warn content`) + } else if (labelValueDef.blurs === 'media') { + if (pref === 'hide') { + return _(msg`Blur images and filter from feeds`) + } + return _(msg`Blur images`) + } else if (labelValueDef.severity === 'alert') { + if (pref === 'hide') { + return _(msg`Show warning and filter from feeds`) + } + return _(msg`Show warning`) + } else if (labelValueDef.severity === 'inform') { + if (pref === 'hide') { + return _(msg`Show badge and filter from feeds`) + } + return _(msg`Show badge`) + } else { + if (pref === 'hide') { + return _(msg`Filter from feeds`) + } + return _(msg`Disabled`) + } +} diff --git a/src/lib/moderation/useLabelInfo.ts b/src/lib/moderation/useLabelInfo.ts new file mode 100644 index 000000000..b1cffe1e7 --- /dev/null +++ b/src/lib/moderation/useLabelInfo.ts @@ -0,0 +1,100 @@ +import { + ComAtprotoLabelDefs, + AppBskyLabelerDefs, + LABELS, + interpretLabelValueDefinition, + InterpretedLabelValueDefinition, +} from '@atproto/api' +import {useLingui} from '@lingui/react' +import * as bcp47Match from 'bcp-47-match' + +import { + GlobalLabelStrings, + useGlobalLabelStrings, +} from '#/lib/moderation/useGlobalLabelStrings' +import {useLabelDefinitions} from '#/state/preferences' + +export interface LabelInfo { + label: ComAtprotoLabelDefs.Label + def: InterpretedLabelValueDefinition + strings: ComAtprotoLabelDefs.LabelValueDefinitionStrings + labeler: AppBskyLabelerDefs.LabelerViewDetailed | undefined +} + +export function useLabelInfo(label: ComAtprotoLabelDefs.Label): LabelInfo { + const {i18n} = useLingui() + const {labelDefs, labelers} = useLabelDefinitions() + const globalLabelStrings = useGlobalLabelStrings() + const def = getDefinition(labelDefs, label) + return { + label, + def, + strings: getLabelStrings(i18n.locale, globalLabelStrings, def), + labeler: labelers.find(labeler => label.src === labeler.creator.did), + } +} + +export function getDefinition( + labelDefs: Record<string, InterpretedLabelValueDefinition[]>, + label: ComAtprotoLabelDefs.Label, +): InterpretedLabelValueDefinition { + // check local definitions + const customDef = + !label.val.startsWith('!') && + labelDefs[label.src]?.find( + def => def.identifier === label.val && def.definedBy === label.src, + ) + if (customDef) { + return customDef + } + + // check global definitions + const globalDef = LABELS[label.val as keyof typeof LABELS] + if (globalDef) { + return globalDef + } + + // fallback to a noop definition + return interpretLabelValueDefinition( + { + identifier: label.val, + severity: 'none', + blurs: 'none', + defaultSetting: 'ignore', + locales: [], + }, + label.src, + ) +} + +export function getLabelStrings( + locale: string, + globalLabelStrings: GlobalLabelStrings, + def: InterpretedLabelValueDefinition, +): ComAtprotoLabelDefs.LabelValueDefinitionStrings { + if (!def.definedBy) { + // global definition, look up strings + if (def.identifier in globalLabelStrings) { + return globalLabelStrings[ + def.identifier + ] as ComAtprotoLabelDefs.LabelValueDefinitionStrings + } + } else { + // try to find locale match in the definition's strings + const localeMatch = def.locales.find( + strings => bcp47Match.basicFilter(locale, strings.lang).length > 0, + ) + if (localeMatch) { + return localeMatch + } + // fall back to the zero item if no match + if (def.locales[0]) { + return def.locales[0] + } + } + return { + lang: locale, + name: def.identifier, + description: `Labeled "${def.identifier}"`, + } +} diff --git a/src/lib/moderation/useModerationCauseDescription.ts b/src/lib/moderation/useModerationCauseDescription.ts new file mode 100644 index 000000000..46771e958 --- /dev/null +++ b/src/lib/moderation/useModerationCauseDescription.ts @@ -0,0 +1,146 @@ +import React from 'react' +import { + BSKY_LABELER_DID, + ModerationCause, + ModerationCauseSource, +} from '@atproto/api' +import {msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {getDefinition, getLabelStrings} from './useLabelInfo' +import {useLabelDefinitions} from '#/state/preferences' +import {useGlobalLabelStrings} from './useGlobalLabelStrings' + +import {Props as SVGIconProps} from '#/components/icons/common' +import {Warning_Stroke2_Corner0_Rounded as Warning} from '#/components/icons/Warning' +import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo' +import {EyeSlash_Stroke2_Corner0_Rounded as EyeSlash} from '#/components/icons/EyeSlash' +import {CircleBanSign_Stroke2_Corner0_Rounded as CircleBanSign} from '#/components/icons/CircleBanSign' + +export interface ModerationCauseDescription { + icon: React.ComponentType<SVGIconProps> + name: string + description: string + source?: string + sourceType?: ModerationCauseSource['type'] +} + +export function useModerationCauseDescription( + cause: ModerationCause | undefined, +): ModerationCauseDescription { + const {_, i18n} = useLingui() + const {labelDefs, labelers} = useLabelDefinitions() + const globalLabelStrings = useGlobalLabelStrings() + + return React.useMemo(() => { + if (!cause) { + return { + icon: Warning, + name: _(msg`Content Warning`), + description: _( + msg`Moderator has chosen to set a general warning on the content.`, + ), + } + } + if (cause.type === 'blocking') { + if (cause.source.type === 'list') { + return { + icon: CircleBanSign, + name: _(msg`User Blocked by "${cause.source.list.name}"`), + description: _( + msg`You have blocked this user. You cannot view their content.`, + ), + } + } else { + return { + icon: CircleBanSign, + name: _(msg`User Blocked`), + description: _( + msg`You have blocked this user. You cannot view their content.`, + ), + } + } + } + if (cause.type === 'blocked-by') { + return { + icon: CircleBanSign, + name: _(msg`User Blocking You`), + description: _( + msg`This user has blocked you. You cannot view their content.`, + ), + } + } + if (cause.type === 'block-other') { + return { + icon: CircleBanSign, + name: _(msg`Content Not Available`), + description: _( + msg`This content is not available because one of the users involved has blocked the other.`, + ), + } + } + if (cause.type === 'muted') { + if (cause.source.type === 'list') { + return { + icon: EyeSlash, + name: _(msg`Muted by "${cause.source.list.name}"`), + description: _(msg`You have muted this user`), + } + } else { + return { + icon: EyeSlash, + name: _(msg`Account Muted`), + description: _(msg`You have muted this account.`), + } + } + } + if (cause.type === 'mute-word') { + return { + icon: EyeSlash, + name: _(msg`Post Hidden by Muted Word`), + description: _( + msg`You've chosen to hide a word or tag within this post.`, + ), + } + } + if (cause.type === 'hidden') { + return { + icon: EyeSlash, + name: _(msg`Post Hidden by You`), + description: _(msg`You have hidden this post`), + } + } + if (cause.type === 'label') { + const def = cause.labelDef || getDefinition(labelDefs, cause.label) + const strings = getLabelStrings(i18n.locale, globalLabelStrings, def) + const labeler = labelers.find(l => l.creator.did === cause.label.src) + let source = + labeler?.creator.displayName || + (labeler?.creator.handle ? '@' + labeler?.creator.handle : undefined) + if (!source) { + if (cause.label.src === BSKY_LABELER_DID) { + source = 'Bluesky Moderation' + } else { + source = cause.label.src + } + } + return { + icon: + def.identifier === '!no-unauthenticated' + ? EyeSlash + : def.severity === 'alert' + ? Warning + : CircleInfo, + name: strings.name, + description: strings.description, + source, + sourceType: cause.source.type, + } + } + // should never happen + return { + icon: CircleInfo, + name: '', + description: ``, + } + }, [labelDefs, labelers, globalLabelStrings, cause, _, i18n.locale]) +} diff --git a/src/lib/moderation/useReportOptions.ts b/src/lib/moderation/useReportOptions.ts new file mode 100644 index 000000000..e00170594 --- /dev/null +++ b/src/lib/moderation/useReportOptions.ts @@ -0,0 +1,94 @@ +import {msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {useMemo} from 'react' +import {ComAtprotoModerationDefs} from '@atproto/api' + +export interface ReportOption { + reason: string + title: string + description: string +} + +interface ReportOptions { + account: ReportOption[] + post: ReportOption[] + list: ReportOption[] + feedgen: ReportOption[] + other: ReportOption[] +} + +export function useReportOptions(): ReportOptions { + const {_} = useLingui() + return useMemo(() => { + const other = { + reason: ComAtprotoModerationDefs.REASONOTHER, + title: _(msg`Other`), + description: _(msg`An issue not included in these options`), + } + const common = [ + { + reason: ComAtprotoModerationDefs.REASONRUDE, + title: _(msg`Anti-Social Behavior`), + description: _(msg`Harassment, trolling, or intolerance`), + }, + { + reason: ComAtprotoModerationDefs.REASONVIOLATION, + title: _(msg`Illegal and Urgent`), + description: _(msg`Glaring violations of law or terms of service`), + }, + other, + ] + return { + account: [ + { + reason: ComAtprotoModerationDefs.REASONMISLEADING, + title: _(msg`Misleading Account`), + description: _( + msg`Impersonation or false claims about identity or affiliation`, + ), + }, + { + reason: ComAtprotoModerationDefs.REASONSPAM, + title: _(msg`Frequently Posts Unwanted Content`), + description: _(msg`Spam; excessive mentions or replies`), + }, + { + reason: ComAtprotoModerationDefs.REASONVIOLATION, + title: _(msg`Name or Description Violates Community Standards`), + description: _(msg`Terms used violate community standards`), + }, + other, + ], + post: [ + { + reason: ComAtprotoModerationDefs.REASONSPAM, + title: _(msg`Spam`), + description: _(msg`Excessive mentions or replies`), + }, + { + reason: ComAtprotoModerationDefs.REASONSEXUAL, + title: _(msg`Unwanted Sexual Content`), + description: _(msg`Nudity or pornography not labeled as such`), + }, + ...common, + ], + list: [ + { + reason: ComAtprotoModerationDefs.REASONVIOLATION, + title: _(msg`Name or Description Violates Community Standards`), + description: _(msg`Terms used violate community standards`), + }, + ...common, + ], + feedgen: [ + { + reason: ComAtprotoModerationDefs.REASONVIOLATION, + title: _(msg`Name or Description Violates Community Standards`), + description: _(msg`Terms used violate community standards`), + }, + ...common, + ], + other: common, + } + }, [_]) +} diff --git a/src/lib/react-query.ts b/src/lib/react-query.ts index 7fe3fe7a4..d6cd3c54b 100644 --- a/src/lib/react-query.ts +++ b/src/lib/react-query.ts @@ -1,7 +1,14 @@ import {AppState, AppStateStatus} from 'react-native' import {QueryClient, focusManager} from '@tanstack/react-query' +import {createAsyncStoragePersister} from '@tanstack/query-async-storage-persister' +import AsyncStorage from '@react-native-async-storage/async-storage' +import {PersistQueryClientProviderProps} from '@tanstack/react-query-persist-client' + import {isNative} from '#/platform/detection' +// any query keys in this array will be persisted to AsyncStorage +const STORED_CACHE_QUERY_KEYS = ['labelers-detailed-info'] + focusManager.setEventListener(onFocus => { if (isNative) { const subscription = AppState.addEventListener( @@ -48,3 +55,16 @@ export const queryClient = new QueryClient({ }, }, }) + +export const asyncStoragePersister = createAsyncStoragePersister({ + storage: AsyncStorage, + key: 'queryCache', +}) + +export const dehydrateOptions: PersistQueryClientProviderProps['persistOptions']['dehydrateOptions'] = + { + shouldDehydrateMutation: (_: any) => false, + shouldDehydrateQuery: query => { + return STORED_CACHE_QUERY_KEYS.includes(String(query.queryKey[0])) + }, + } diff --git a/src/lib/routes/types.ts b/src/lib/routes/types.ts index 6756a62a6..95af2f237 100644 --- a/src/lib/routes/types.ts +++ b/src/lib/routes/types.ts @@ -21,7 +21,9 @@ export type CommonNavigatorParams = { PostRepostedBy: {name: string; rkey: string} ProfileFeed: {name: string; rkey: string} ProfileFeedLikedBy: {name: string; rkey: string} + ProfileLabelerLikedBy: {name: string} Debug: undefined + DebugMod: undefined Log: undefined Support: undefined PrivacyPolicy: undefined diff --git a/src/lib/sharing.ts b/src/lib/sharing.ts index b294d7464..9f402f873 100644 --- a/src/lib/sharing.ts +++ b/src/lib/sharing.ts @@ -12,9 +12,9 @@ import {Share} from 'react-native' */ export async function shareUrl(url: string) { if (isAndroid) { - Share.share({message: url}) + await Share.share({message: url}) } else if (isIOS) { - Share.share({url}) + await Share.share({url}) } else { // React Native Share is not supported by web. Web Share API // has increasing but not full support, so default to clipboard diff --git a/src/lib/statsig/events.ts b/src/lib/statsig/events.ts new file mode 100644 index 000000000..fa7e597fb --- /dev/null +++ b/src/lib/statsig/events.ts @@ -0,0 +1,47 @@ +export type LogEvents = { + init: { + initMs: number + } + 'feed:endReached': { + feedType: string + itemCount: number + } + 'post:create': { + imageCount: number + isReply: boolean + hasLink: boolean + hasQuote: boolean + langs: string + logContext: 'Composer' + } + 'post:like': { + logContext: 'FeedItem' | 'PostThreadItem' | 'Post' + } + 'post:repost': { + logContext: 'FeedItem' | 'PostThreadItem' | 'Post' + } + 'post:unlike': { + logContext: 'FeedItem' | 'PostThreadItem' | 'Post' + } + 'post:unrepost': { + logContext: 'FeedItem' | 'PostThreadItem' | 'Post' + } + 'profile:follow': { + logContext: + | 'RecommendedFollowsItem' + | 'PostThreadItem' + | 'ProfileCard' + | 'ProfileHeader' + | 'ProfileHeaderSuggestedFollows' + | 'ProfileMenu' + } + 'profile:unfollow': { + logContext: + | 'RecommendedFollowsItem' + | 'PostThreadItem' + | 'ProfileCard' + | 'ProfileHeader' + | 'ProfileHeaderSuggestedFollows' + | 'ProfileMenu' + } +} diff --git a/src/lib/statsig/statsig.tsx b/src/lib/statsig/statsig.tsx index 6d9ebeb09..5745d204a 100644 --- a/src/lib/statsig/statsig.tsx +++ b/src/lib/statsig/statsig.tsx @@ -6,6 +6,9 @@ import { } from 'statsig-react-native-expo' import {useSession} from '../../state/session' import {sha256} from 'js-sha256' +import {LogEvents} from './events' + +export type {LogEvents} const statsigOptions = { environment: { @@ -17,12 +20,28 @@ const statsigOptions = { initTimeoutMs: 1, } -export function logEvent( - eventName: string, - value?: string | number | null, - metadata?: Record<string, string> | null, +type FlatJSONRecord = Record< + string, + string | number | boolean | null | undefined +> + +let getCurrentRouteName: () => string | null | undefined = () => null + +export function attachRouteToLogEvents( + getRouteName: () => string | null | undefined, +) { + getCurrentRouteName = getRouteName +} + +export function logEvent<E extends keyof LogEvents>( + eventName: E & string, + rawMetadata: LogEvents[E] & FlatJSONRecord, ) { - Statsig.logEvent(eventName, value, metadata) + const fullMetadata = { + ...rawMetadata, + } as Record<string, string> // Statsig typings are unnecessarily strict here. + fullMetadata.routeName = getCurrentRouteName() ?? '(Uninitialized)' + Statsig.logEvent(eventName, null, fullMetadata) } export function useGate(gateName: string) { diff --git a/src/lib/statsig/statsig.web.tsx b/src/lib/statsig/statsig.web.tsx deleted file mode 100644 index d1c912019..000000000 --- a/src/lib/statsig/statsig.web.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import React from 'react' -import { - Statsig, - StatsigProvider, - useGate as useStatsigGate, -} from 'statsig-react' -import {useSession} from '../../state/session' -import {sha256} from 'js-sha256' - -const statsigOptions = { - environment: { - tier: process.env.NODE_ENV === 'development' ? 'development' : 'production', - }, - // Don't block on waiting for network. The fetched config will kick in on next load. - // This ensures the UI is always consistent and doesn't update mid-session. - // Note this makes cold load (no local storage) and private mode return `false` for all gates. - initTimeoutMs: 1, -} - -export function logEvent( - eventName: string, - value?: string | number | null, - metadata?: Record<string, string> | null, -) { - Statsig.logEvent(eventName, value, metadata) -} - -export function useGate(gateName: string) { - const {isLoading, value} = useStatsigGate(gateName) - if (isLoading) { - // This should not happen because of waitForInitialization={true}. - console.error('Did not expected isLoading to ever be true.') - } - return value -} - -function toStatsigUser(did: string | undefined) { - let userID: string | undefined - if (did) { - userID = sha256(did) - } - return {userID} -} - -export function Provider({children}: {children: React.ReactNode}) { - const {currentAccount} = useSession() - const currentStatsigUser = React.useMemo( - () => toStatsigUser(currentAccount?.did), - [currentAccount?.did], - ) - - React.useEffect(() => { - function refresh() { - // Intentionally refetching the config using the JS SDK rather than React SDK - // so that the new config is stored in cache but isn't used during this session. - // It will kick in for the next reload. - Statsig.updateUser(currentStatsigUser) - } - const id = setInterval(refresh, 3 * 60e3 /* 3 min */) - return () => clearInterval(id) - }, [currentStatsigUser]) - - return ( - <StatsigProvider - sdkKey="client-SXJakO39w9vIhl3D44u8UupyzFl4oZ2qPIkjwcvuPsV" - mountKey={currentStatsigUser.userID} - user={currentStatsigUser} - // This isn't really blocking due to short initTimeoutMs above. - // However, it ensures `isLoading` is always `false`. - waitForInitialization={true} - options={statsigOptions}> - {children} - </StatsigProvider> - ) -} diff --git a/src/lib/strings/display-names.ts b/src/lib/strings/display-names.ts index 75383dd4f..e0f23fa2c 100644 --- a/src/lib/strings/display-names.ts +++ b/src/lib/strings/display-names.ts @@ -1,5 +1,4 @@ import {ModerationUI} from '@atproto/api' -import {describeModerationCause} from '../moderation' // \u2705 = ✅ // \u2713 = ✓ @@ -14,7 +13,7 @@ export function sanitizeDisplayName( moderation?: ModerationUI, ): string { if (moderation?.blur) { - return `âš ${describeModerationCause(moderation.cause, 'account').name}` + return '' } if (typeof str === 'string') { return str.replace(CHECK_MARKS_RE, '').replace(CONTROL_CHARS_RE, '').trim() diff --git a/src/lib/strings/embed-player.ts b/src/lib/strings/embed-player.ts index 1cf3b1293..ee7328478 100644 --- a/src/lib/strings/embed-player.ts +++ b/src/lib/strings/embed-player.ts @@ -2,6 +2,15 @@ import {Dimensions} from 'react-native' import {isWeb} from 'platform/detection' const {height: SCREEN_HEIGHT} = Dimensions.get('window') +const IFRAME_HOST = isWeb + ? // @ts-ignore only for web + window.location.host === 'localhost:8100' + ? 'http://localhost:8100' + : 'https://bsky.app' + : __DEV__ && !process.env.JEST_WORKER_ID + ? 'http://localhost:8100' + : 'https://bsky.app' + export const embedPlayerSources = [ 'youtube', 'youtubeShorts', @@ -74,7 +83,7 @@ export function parseEmbedPlayerFromUrl( return { type: 'youtube_video', source: 'youtube', - playerUri: `https://bsky.app/iframe/youtube.html?videoId=${videoId}&start=${seek}`, + playerUri: `${IFRAME_HOST}/iframe/youtube.html?videoId=${videoId}&start=${seek}`, } } } @@ -93,7 +102,7 @@ export function parseEmbedPlayerFromUrl( type: page === 'shorts' ? 'youtube_short' : 'youtube_video', source: page === 'shorts' ? 'youtubeShorts' : 'youtube', hideDetails: page === 'shorts' ? true : undefined, - playerUri: `https://bsky.app/iframe/youtube.html?videoId=${videoId}&start=${seek}`, + playerUri: `${IFRAME_HOST}/iframe/youtube.html?videoId=${videoId}&start=${seek}`, } } } diff --git a/src/lib/strings/url-helpers.ts b/src/lib/strings/url-helpers.ts index 820311e4e..70a2b7069 100644 --- a/src/lib/strings/url-helpers.ts +++ b/src/lib/strings/url-helpers.ts @@ -4,6 +4,23 @@ import TLDs from 'tlds' import psl from 'psl' export const BSKY_APP_HOST = 'https://bsky.app' +const BSKY_TRUSTED_HOSTS = [ + 'bsky.app', + 'bsky.social', + 'blueskyweb.xyz', + 'blueskyweb.zendesk.com', + ...(__DEV__ ? ['localhost:19006', 'localhost:8100'] : []), +] + +/* + * This will allow any BSKY_TRUSTED_HOSTS value by itself or with a subdomain. + * It will also allow relative paths like /profile as well as #. + */ +const TRUSTED_REGEX = new RegExp( + `^(http(s)?://(([\\w-]+\\.)?${BSKY_TRUSTED_HOSTS.join( + '|([\\w-]+\\.)?', + )})|/|#)`, +) export function isValidDomain(str: string): boolean { return !!TLDs.find(tld => { @@ -86,6 +103,10 @@ export function isExternalUrl(url: string): boolean { return external || rss } +export function isTrustedUrl(url: string): boolean { + return TRUSTED_REGEX.test(url) +} + export function isBskyPostUrl(url: string): boolean { if (isBskyAppUrl(url)) { try { @@ -163,8 +184,8 @@ export function feedUriToHref(url: string): string { export function linkRequiresWarning(uri: string, label: string) { const labelDomain = labelToDomain(label) - // If the uri started with a / we know it is internal. - if (isRelativeUrl(uri)) { + // We should trust any relative URL or a # since we know it links to internal content + if (isRelativeUrl(uri) || uri === '#') { return false } @@ -176,18 +197,11 @@ export function linkRequiresWarning(uri: string, label: string) { } const host = urip.hostname.toLowerCase() - // Hosts that end with bsky.app or bsky.social should be trusted by default. - if ( - host.endsWith('bsky.app') || - host.endsWith('bsky.social') || - host.endsWith('blueskyweb.xyz') - ) { - // if this is a link to internal content, - // warn if it represents itself as a URL to another app + if (isTrustedUrl(uri)) { + // if this is a link to internal content, warn if it represents itself as a URL to another app return !!labelDomain && labelDomain !== host && isPossiblyAUrl(labelDomain) } else { - // if this is a link to external content, - // warn if the label doesnt match the target + // if this is a link to external content, warn if the label doesnt match the target if (!labelDomain) { return true } diff --git a/src/lib/themes.ts b/src/lib/themes.ts index bd75aabea..6fada40a7 100644 --- a/src/lib/themes.ts +++ b/src/lib/themes.ts @@ -9,7 +9,7 @@ export const defaultTheme: Theme = { palette: { default: { background: lightPalette.white, - backgroundLight: lightPalette.contrast_50, + backgroundLight: lightPalette.contrast_25, text: lightPalette.black, textLight: lightPalette.contrast_700, textInverted: lightPalette.white, diff --git a/src/locale/locales/ca/messages.po b/src/locale/locales/ca/messages.po index 927599ab4..0fd11dab6 100644 --- a/src/locale/locales/ca/messages.po +++ b/src/locale/locales/ca/messages.po @@ -90,12 +90,12 @@ msgstr "S'ha aplicat una advertència de contingut a {0}." msgid "A new version of the app is available. Please update to continue using the app." msgstr "Hi ha una nova versió d'aquesta aplicació. Actualitza-la per continuar." -#: src/view/com/util/ViewHeader.tsx:83 +#: src/view/com/util/ViewHeader.tsx:89 #: src/view/screens/Search/Search.tsx:647 msgid "Access navigation links and settings" msgstr "Accedeix als enllaços de navegació i configuració" -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:51 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:52 msgid "Access profile and other navigation links" msgstr "Accedeix al perfil i altres enllaços de navegació" @@ -142,11 +142,11 @@ msgstr "Compte desbloquejat" msgid "Account unmuted" msgstr "Compte no silenciat" -#: src/components/dialogs/MutedWords.tsx:147 +#: src/components/dialogs/MutedWords.tsx:165 #: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:150 #: src/view/com/modals/ListAddRemoveUsers.tsx:264 #: src/view/com/modals/UserAddRemoveLists.tsx:219 -#: src/view/screens/ProfileList.tsx:812 +#: src/view/screens/ProfileList.tsx:813 msgid "Add" msgstr "Afegeix" @@ -154,7 +154,7 @@ msgstr "Afegeix" msgid "Add a content warning" msgstr "Afegeix una advertència de contingut" -#: src/view/screens/ProfileList.tsx:802 +#: src/view/screens/ProfileList.tsx:803 msgid "Add a user to this list" msgstr "Afegeix un usuari a aquesta llista" @@ -192,11 +192,11 @@ msgstr "Afegeix una targeta a l'enllaç" msgid "Add link card:" msgstr "Afegeix una targeta a l'enllaç:" -#: src/components/dialogs/MutedWords.tsx:140 +#: src/components/dialogs/MutedWords.tsx:158 msgid "Add mute word for configured settings" msgstr "" -#: src/components/dialogs/MutedWords.tsx:74 +#: src/components/dialogs/MutedWords.tsx:87 msgid "Add muted words and tags" msgstr "" @@ -244,12 +244,12 @@ msgstr "Avançat" #: src/view/screens/Feeds.tsx:666 msgid "All the feeds you've saved, right in one place." -msgstr "" +msgstr "Tots els canals que has desat, en un sol lloc." #: src/view/com/auth/login/ForgotPasswordForm.tsx:221 #: src/view/com/modals/ChangePassword.tsx:168 msgid "Already have a code?" -msgstr "" +msgstr "Ja tens un codi?" #: src/view/com/auth/login/ChooseAccountForm.tsx:98 msgid "Already signed in as @{0}" @@ -280,14 +280,14 @@ msgstr "S'ha enviat un correu a la teva adreça prèvia, {0}. Inclou un codi de msgid "An issue occurred, please try again." msgstr "Hi ha hagut un problema, prova-ho de nou" -#: src/view/com/notifications/FeedItem.tsx:236 +#: src/view/com/notifications/FeedItem.tsx:237 #: src/view/com/threadgate/WhoCanReply.tsx:178 msgid "and" msgstr "i" #: src/screens/Onboarding/index.tsx:32 msgid "Animals" -msgstr "" +msgstr "Animals" #: src/view/screens/LanguageSettings.tsx:95 msgid "App Language" @@ -313,13 +313,14 @@ msgstr "Configuració de la contrasenya d'aplicació" #~ msgid "App passwords" #~ msgstr "Contrasenyes de l'aplicació" -#: src/Navigation.tsx:237 +#: src/Navigation.tsx:239 #: src/view/screens/AppPasswords.tsx:187 #: src/view/screens/Settings/index.tsx:684 msgid "App Passwords" msgstr "Contrasenyes de l'aplicació" -#: src/view/com/util/forms/PostDropdownBtn.tsx:295 +#: src/view/com/util/forms/PostDropdownBtn.tsx:337 +#: src/view/com/util/forms/PostDropdownBtn.tsx:346 msgid "Appeal content warning" msgstr "Advertència d'apel·lació sobre el contingut" @@ -350,12 +351,12 @@ msgstr "Confirmes que vols eliminar la contrasenya de l'aplicació \"{name}\"?" msgid "Are you sure you'd like to discard this draft?" msgstr "Confirmes que vols descartar aquest esborrany?" -#: src/components/dialogs/MutedWords.tsx:233 +#: src/components/dialogs/MutedWords.tsx:282 #: src/view/screens/ProfileList.tsx:365 msgid "Are you sure?" msgstr "Ho confirmes?" -#: src/view/com/util/forms/PostDropdownBtn.tsx:278 +#: src/view/com/util/forms/PostDropdownBtn.tsx:322 msgid "Are you sure? This cannot be undone." msgstr "Ho confirmes? Aquesta acció no es pot desfer." @@ -365,7 +366,7 @@ msgstr "Està s escrivint en <0>{0}</0>?" #: src/screens/Onboarding/index.tsx:26 msgid "Art" -msgstr "" +msgstr "Art" #: src/view/com/modals/SelfLabel.tsx:123 msgid "Artistic or non-erotic nudity." @@ -381,7 +382,7 @@ msgstr "Nuesa artÃstica o no eròtica." #: src/view/com/post-thread/PostThread.tsx:522 #: src/view/com/post-thread/PostThread.tsx:530 #: src/view/com/profile/ProfileHeader.tsx:649 -#: src/view/com/util/ViewHeader.tsx:81 +#: src/view/com/util/ViewHeader.tsx:87 msgid "Back" msgstr "Endarrere" @@ -392,13 +393,13 @@ msgstr "Endarrere" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:136 msgid "Based on your interest in {interestsText}" -msgstr "" +msgstr "Segons els teus interessos en {interestsText}" #: src/view/screens/Settings/index.tsx:523 msgid "Basics" msgstr "Conceptes bà sics" -#: src/view/com/auth/create/Step1.tsx:250 +#: src/view/com/auth/create/Step1.tsx:227 #: src/view/com/modals/BirthDateSettings.tsx:73 msgid "Birthday" msgstr "Aniversari" @@ -437,7 +438,7 @@ msgstr "Bloquejada" msgid "Blocked accounts" msgstr "Comptes bloquejats" -#: src/Navigation.tsx:130 +#: src/Navigation.tsx:132 #: src/view/screens/ModerationBlockedAccounts.tsx:107 msgid "Blocked Accounts" msgstr "Comptes bloquejats" @@ -471,7 +472,7 @@ msgstr "Bluesky" #: src/view/com/auth/server-input/index.tsx:150 msgid "Bluesky is an open network where you can choose your hosting provider. Custom hosting is now available in beta for developers." -msgstr "" +msgstr "Bluesky és una xarxa oberta on pots escollir el teu proveïdor d'allotjament. L'allotjament personalitzat està disponible en beta per a desenvolupadors" #: src/view/com/auth/onboarding/WelcomeDesktop.tsx:80 #: src/view/com/auth/onboarding/WelcomeMobile.tsx:80 @@ -489,8 +490,8 @@ msgid "Bluesky is public." msgstr "Bluesky és públic." #: src/view/com/modals/Waitlist.tsx:70 -msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon." -msgstr "Bluesky utilitza les invitacions per construir una comunitat saludable. Si no coneixes ningú amb invitacions, pots apuntar-te a la llista d'espera i te n'enviarem una aviat." +#~ msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon." +#~ msgstr "Bluesky utilitza les invitacions per construir una comunitat saludable. Si no coneixes ningú amb invitacions, pots apuntar-te a la llista d'espera i te n'enviarem una aviat." #: src/view/screens/Moderation.tsx:245 msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private." @@ -502,7 +503,7 @@ msgstr "Bluesky no mostrarà el teu perfil ni les publicacions als usuaris que n #: src/screens/Onboarding/index.tsx:33 msgid "Books" -msgstr "" +msgstr "Llibres" #: src/view/screens/Settings/index.tsx:859 msgid "Build version {0} {1}" @@ -543,7 +544,7 @@ msgstr "Cà mera" msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must be at least 4 characters long, but no more than 32 characters long." msgstr "Només pot tenir lletres, números, espais, guions i guions baixos. Ha de tenir almenys 4 carà cters i no més de 32." -#: src/components/Prompt.tsx:91 +#: src/components/Prompt.tsx:101 #: src/view/com/composer/Composer.tsx:307 #: src/view/com/composer/Composer.tsx:312 #: src/view/com/modals/ChangeEmail.tsx:218 @@ -558,7 +559,6 @@ msgstr "Només pot tenir lletres, números, espais, guions i guions baixos. Ha d #: src/view/com/modals/Repost.tsx:87 #: src/view/com/modals/VerifyEmail.tsx:247 #: src/view/com/modals/VerifyEmail.tsx:253 -#: src/view/com/modals/Waitlist.tsx:142 #: src/view/screens/Search/Search.tsx:716 #: src/view/shell/desktop/Search.tsx:238 msgid "Cancel" @@ -604,8 +604,8 @@ msgid "Cancel search" msgstr "Cancel·la la cerca" #: src/view/com/modals/Waitlist.tsx:136 -msgid "Cancel waitlist signup" -msgstr "Cancel·la la inscripció a la llista d'espera" +#~ msgid "Cancel waitlist signup" +#~ msgstr "Cancel·la la inscripció a la llista d'espera" #: src/view/screens/Settings/index.tsx:334 msgctxt "action" @@ -631,11 +631,11 @@ msgstr "Canvia el meu correu" #: src/view/screens/Settings/index.tsx:732 msgid "Change password" -msgstr "" +msgstr "Canvia la contrasenya" #: src/view/screens/Settings/index.tsx:741 msgid "Change Password" -msgstr "" +msgstr "Canvia la contrasenya" #: src/view/com/composer/select-language/SuggestedLanguage.tsx:73 msgid "Change post language to {0}" @@ -643,7 +643,7 @@ msgstr "Canvia l'idioma de la publicació a {0}" #: src/view/screens/Settings/index.tsx:733 msgid "Change your Bluesky password" -msgstr "" +msgstr "Canvia la teva contrasenya de Bluesky" #: src/view/com/modals/ChangeEmail.tsx:109 msgid "Change Your Email" @@ -652,7 +652,7 @@ msgstr "Canvia el teu correu" #: src/screens/Deactivated.tsx:72 #: src/screens/Deactivated.tsx:76 msgid "Check my status" -msgstr "" +msgstr "Comprova el meu estat" #: src/view/com/auth/onboarding/RecommendedFeeds.tsx:121 msgid "Check out some recommended feeds. Tap + to add them to your list of pinned feeds." @@ -680,7 +680,7 @@ msgstr "Tria un servei" #: src/screens/Onboarding/StepFinished.tsx:135 msgid "Choose the algorithms that power your custom feeds." -msgstr "" +msgstr "Tria els algoritmes que alimentaran els teus canals personalitzats." #: src/view/com/auth/onboarding/WelcomeDesktop.tsx:83 #: src/view/com/auth/onboarding/WelcomeMobile.tsx:83 @@ -689,9 +689,9 @@ msgstr "Tria els algoritmes que potenciaran la teva experiència amb els canals #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:103 msgid "Choose your main feeds" -msgstr "" +msgstr "Tria els teus canals principals" -#: src/view/com/auth/create/Step1.tsx:219 +#: src/view/com/auth/create/Step1.tsx:196 msgid "Choose your password" msgstr "Tria la teva contrasenya" @@ -722,22 +722,25 @@ msgstr "Esborra la cerca" msgid "click here" msgstr "clica aquÃ" -#: src/components/RichText.tsx:189 -#: src/components/TagMenu/index.web.tsx:125 +#: src/components/TagMenu/index.web.tsx:138 msgid "Click here to open tag menu for {tag}" msgstr "" +#: src/components/RichText.tsx:191 +msgid "Click here to open tag menu for #{tag}" +msgstr "" + #: src/screens/Onboarding/index.tsx:35 msgid "Climate" -msgstr "" +msgstr "Clima" #: src/view/com/modals/ChangePassword.tsx:265 #: src/view/com/modals/ChangePassword.tsx:268 msgid "Close" -msgstr "" +msgstr "Tanca" -#: src/components/Dialog/index.web.tsx:80 -#: src/components/Dialog/index.web.tsx:194 +#: src/components/Dialog/index.web.tsx:84 +#: src/components/Dialog/index.web.tsx:198 msgid "Close active dialog" msgstr "Tanca el dià leg actiu" @@ -761,7 +764,7 @@ msgstr "Tanca el visor d'imatges" msgid "Close navigation footer" msgstr "Tanca el peu de la navegació" -#: src/components/TagMenu/index.tsx:266 +#: src/components/TagMenu/index.tsx:262 msgid "Close this dialog" msgstr "" @@ -781,26 +784,26 @@ msgstr "Tanca l'editor de la publicació i descarta l'esborrany" msgid "Closes viewer for header image" msgstr "Tanca la visualització de la imatge de la capçalera" -#: src/view/com/notifications/FeedItem.tsx:317 +#: src/view/com/notifications/FeedItem.tsx:318 msgid "Collapses list of users for a given notification" msgstr "Plega la llista d'usuaris per una notificació concreta" #: src/screens/Onboarding/index.tsx:41 msgid "Comedy" -msgstr "" +msgstr "Comèdia" #: src/screens/Onboarding/index.tsx:27 msgid "Comics" -msgstr "" +msgstr "Còmics" -#: src/Navigation.tsx:227 +#: src/Navigation.tsx:229 #: src/view/screens/CommunityGuidelines.tsx:32 msgid "Community Guidelines" msgstr "Directrius de la comunitat" #: src/screens/Onboarding/StepFinished.tsx:148 msgid "Complete onboarding and start using your account" -msgstr "" +msgstr "Finalitza el registre i comença a utilitzar el teu compte" #: src/view/com/auth/create/Step3.tsx:73 msgid "Complete the challenge" @@ -816,9 +819,9 @@ msgstr "Redacta una resposta" #: src/screens/Onboarding/StepModeration/ModerationOption.tsx:67 msgid "Configure content filtering setting for category: {0}" -msgstr "" +msgstr "Configura els filtres de continguts per la categoria: {0}" -#: src/components/Prompt.tsx:113 +#: src/components/Prompt.tsx:124 #: src/view/com/modals/AppealLabel.tsx:98 #: src/view/com/modals/SelfLabel.tsx:154 #: src/view/com/modals/VerifyEmail.tsx:231 @@ -858,8 +861,8 @@ msgid "Confirmation code" msgstr "Codi de confirmació" #: src/view/com/modals/Waitlist.tsx:120 -msgid "Confirms signing up {email} to the waitlist" -msgstr "Confirma afegir {email} a la llista d'espera" +#~ msgid "Confirms signing up {email} to the waitlist" +#~ msgstr "Confirma afegir {email} a la llista d'espera" #: src/view/com/auth/create/CreateAccount.tsx:193 #: src/view/com/auth/login/LoginForm.tsx:278 @@ -911,19 +914,19 @@ msgstr "Continua" #: src/screens/Onboarding/StepModeration/index.tsx:115 #: src/screens/Onboarding/StepTopicalFeeds.tsx:111 msgid "Continue to next step" -msgstr "" +msgstr "Continua" #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:167 msgid "Continue to the next step" -msgstr "" +msgstr "Continua" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:191 msgid "Continue to the next step without following any accounts" -msgstr "" +msgstr "Continua sense seguir cap compte" #: src/screens/Onboarding/index.tsx:44 msgid "Cooking" -msgstr "" +msgstr "Cuina" #: src/view/com/modals/AddAppPasswords.tsx:195 #: src/view/com/modals/InviteCodes.tsx:182 @@ -936,7 +939,7 @@ msgstr "Número de versió copiat en memòria" #: src/view/com/modals/AddAppPasswords.tsx:76 #: src/view/com/modals/InviteCodes.tsx:152 -#: src/view/com/util/forms/PostDropdownBtn.tsx:143 +#: src/view/com/util/forms/PostDropdownBtn.tsx:161 msgid "Copied to clipboard" msgstr "Copiat en memòria" @@ -952,7 +955,8 @@ msgstr "Copia" msgid "Copy link to list" msgstr "Copia l'enllaç a la llista" -#: src/view/com/util/forms/PostDropdownBtn.tsx:184 +#: src/view/com/util/forms/PostDropdownBtn.tsx:231 +#: src/view/com/util/forms/PostDropdownBtn.tsx:237 msgid "Copy link to post" msgstr "Copia l'enllaç a la publicació" @@ -960,11 +964,12 @@ msgstr "Copia l'enllaç a la publicació" msgid "Copy link to profile" msgstr "Copia l'enllaç al perfil" -#: src/view/com/util/forms/PostDropdownBtn.tsx:170 +#: src/view/com/util/forms/PostDropdownBtn.tsx:223 +#: src/view/com/util/forms/PostDropdownBtn.tsx:225 msgid "Copy post text" msgstr "Copia el text de la publicació" -#: src/Navigation.tsx:232 +#: src/Navigation.tsx:234 #: src/view/screens/CopyrightPolicy.tsx:29 msgid "Copyright Policy" msgstr "PolÃtica de drets d'autor" @@ -973,7 +978,7 @@ msgstr "PolÃtica de drets d'autor" msgid "Could not load feed" msgstr "No es pot carregar el canal" -#: src/view/screens/ProfileList.tsx:888 +#: src/view/screens/ProfileList.tsx:893 msgid "Could not load list" msgstr "No es pot carregar la llista" @@ -1022,12 +1027,12 @@ msgstr "Crea una targeta amb una minuatura. La targeta enllaça a {url}" #: src/screens/Onboarding/index.tsx:29 msgid "Culture" -msgstr "" +msgstr "Cultura" #: src/view/com/auth/server-input/index.tsx:95 #: src/view/com/auth/server-input/index.tsx:96 msgid "Custom" -msgstr "" +msgstr "Personalitzat" #: src/view/com/modals/ChangeHandle.tsx:389 msgid "Custom domain" @@ -1036,7 +1041,7 @@ msgstr "Domini personalitzat" #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:106 #: src/view/screens/Feeds.tsx:692 msgid "Custom feeds built by the community bring you new experiences and help you find the content you love." -msgstr "" +msgstr "Els canals personalitzats fets per la comunitat et porten noves experiències i t'ajuden a trobar contingut que t'agradarà ." #: src/view/screens/PreferencesExternalEmbeds.tsx:55 msgid "Customize media from external sites." @@ -1057,7 +1062,7 @@ msgstr "Mode fosc" #: src/view/screens/Settings/index.tsx:498 msgid "Dark Theme" -msgstr "" +msgstr "Tema fosc" #: src/view/screens/Debug.tsx:83 msgid "Debug panel" @@ -1091,13 +1096,14 @@ msgstr "Elimina el meu compte" #: src/view/screens/Settings/index.tsx:784 msgid "Delete My Account…" -msgstr "" +msgstr "Elimina el meu compte…" -#: src/view/com/util/forms/PostDropdownBtn.tsx:273 +#: src/view/com/util/forms/PostDropdownBtn.tsx:317 +#: src/view/com/util/forms/PostDropdownBtn.tsx:326 msgid "Delete post" msgstr "Elimina la publicació" -#: src/view/com/util/forms/PostDropdownBtn.tsx:277 +#: src/view/com/util/forms/PostDropdownBtn.tsx:321 msgid "Delete this post?" msgstr "Vols eliminar aquesta publicació?" @@ -1130,7 +1136,7 @@ msgstr "Vols dir alguna cosa?" #: src/view/screens/Settings/index.tsx:504 msgid "Dim" -msgstr "" +msgstr "Tènue" #: src/view/com/composer/Composer.tsx:151 msgid "Discard" @@ -1155,7 +1161,7 @@ msgstr "Descobreix nous canals personalitzats" #: src/view/screens/Feeds.tsx:689 msgid "Discover New Feeds" -msgstr "" +msgstr "Descobreix nous canals" #: src/view/com/modals/EditProfile.tsx:192 msgid "Display name" @@ -1170,8 +1176,8 @@ msgid "Domain verified!" msgstr "Domini verificat!" #: src/view/com/auth/create/Step1.tsx:170 -msgid "Don't have an invite code?" -msgstr "No tens un codi d'invitació?" +#~ msgid "Don't have an invite code?" +#~ msgstr "No tens un codi d'invitació?" #: src/view/com/auth/onboarding/RecommendedFollows.tsx:86 #: src/view/com/modals/EditImage.tsx:333 @@ -1212,20 +1218,20 @@ msgstr "Fes doble toc per iniciar la sessió" #: src/view/screens/Settings/index.tsx:755 msgid "Download Bluesky account data (repository)" -msgstr "" +msgstr "Descarrega les dades del compte de Bluesky (repositori)" #: src/view/screens/Settings/ExportCarDialog.tsx:59 #: src/view/screens/Settings/ExportCarDialog.tsx:63 msgid "Download CAR file" -msgstr "" +msgstr "Descarrega el fitxer CAR" #: src/view/com/composer/text-input/TextInput.web.tsx:249 msgid "Drop to add images" -msgstr "" +msgstr "Deixa anar per afegir imatges" #: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:111 msgid "Due to Apple policies, adult content can only be enabled on the web after completing sign up." -msgstr "" +msgstr "Degut a les polÃtiques d'Apple, el contingut per a adults només es pot habilitar a la web després de registrar-se" #: src/view/com/modals/EditProfile.tsx:185 msgid "e.g. Alice Roberts" @@ -1273,7 +1279,7 @@ msgstr "Edita els detalls de la llista" msgid "Edit Moderation List" msgstr "Edita la llista de moderació" -#: src/Navigation.tsx:242 +#: src/Navigation.tsx:244 #: src/view/screens/Feeds.tsx:434 #: src/view/screens/SavedFeeds.tsx:84 msgid "Edit My Feeds" @@ -1291,7 +1297,7 @@ msgstr "Edita el perfil" msgid "Edit Profile" msgstr "Edita el perfil" -#: src/view/com/home/HomeHeaderLayout.web.tsx:59 +#: src/view/com/home/HomeHeaderLayout.web.tsx:62 #: src/view/screens/Feeds.tsx:355 msgid "Edit Saved Feeds" msgstr "Edita els meus canals guardats" @@ -1310,16 +1316,15 @@ msgstr "Edita la descripció del teu perfil" #: src/screens/Onboarding/index.tsx:34 msgid "Education" -msgstr "" +msgstr "Ensenyament" -#: src/view/com/auth/create/Step1.tsx:199 +#: src/view/com/auth/create/Step1.tsx:176 #: src/view/com/auth/login/ForgotPasswordForm.tsx:156 #: src/view/com/modals/ChangeEmail.tsx:141 -#: src/view/com/modals/Waitlist.tsx:88 msgid "Email" msgstr "Correu" -#: src/view/com/auth/create/Step1.tsx:190 +#: src/view/com/auth/create/Step1.tsx:167 #: src/view/com/auth/login/ForgotPasswordForm.tsx:147 msgid "Email address" msgstr "Adreça de correu" @@ -1352,7 +1357,7 @@ msgstr "Habilita el contingut per a adults" #: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:76 #: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:77 msgid "Enable adult content in your feeds" -msgstr "" +msgstr "Habilita veure el contingut per adults als teus canals" #: src/view/com/modals/EmbedConsent.tsx:97 msgid "Enable External Media" @@ -1374,8 +1379,8 @@ msgstr "Fi del canal" msgid "Enter a name for this App Password" msgstr "Posa un nom a aquesta contrasenya d'aplicació" -#: src/components/dialogs/MutedWords.tsx:87 -#: src/components/dialogs/MutedWords.tsx:88 +#: src/components/dialogs/MutedWords.tsx:100 +#: src/components/dialogs/MutedWords.tsx:101 msgid "Enter a word or tag" msgstr "" @@ -1389,7 +1394,7 @@ msgstr "Entra el codi de confirmació" #: src/view/com/modals/ChangePassword.tsx:151 msgid "Enter the code you received to change your password." -msgstr "" +msgstr "Introdueix el codi que has rebut per canviar la teva contrasenya." #: src/view/com/modals/ChangeHandle.tsx:371 msgid "Enter the domain you want to use" @@ -1399,16 +1404,16 @@ msgstr "Introdueix el domini que vols utilitzar" msgid "Enter the email you used to create your account. We'll send you a \"reset code\" so you can set a new password." msgstr "Introdueix el correu que vas fer servir per crear el teu compte. T'enviarem un \"codi de restabliment\" perquè puguis posar una nova contrasenya." -#: src/view/com/auth/create/Step1.tsx:251 +#: src/view/com/auth/create/Step1.tsx:228 #: src/view/com/modals/BirthDateSettings.tsx:74 msgid "Enter your birth date" msgstr "Introdueix la teva data de naixement" #: src/view/com/modals/Waitlist.tsx:78 -msgid "Enter your email" -msgstr "Introdueix el teu correu" +#~ msgid "Enter your email" +#~ msgstr "Introdueix el teu correu" -#: src/view/com/auth/create/Step1.tsx:195 +#: src/view/com/auth/create/Step1.tsx:172 msgid "Enter your email address" msgstr "Introdueix el teu correu" @@ -1454,8 +1459,8 @@ msgid "Exits inputting search query" msgstr "Surt de la cerca" #: src/view/com/modals/Waitlist.tsx:138 -msgid "Exits signing up for waitlist with {email}" -msgstr "Surt de la llista d'espera amb el correu {email}" +#~ msgid "Exits signing up for waitlist with {email}" +#~ msgstr "Surt de la llista d'espera amb el correu {email}" #: src/view/com/lightbox/Lightbox.web.tsx:163 msgid "Expand alt text" @@ -1468,12 +1473,12 @@ msgstr "Expandeix o replega la publicació completa a la qual està s responent" #: src/view/screens/Settings/index.tsx:753 msgid "Export my data" -msgstr "" +msgstr "Exporta les meves dades" #: src/view/screens/Settings/ExportCarDialog.tsx:44 #: src/view/screens/Settings/index.tsx:764 msgid "Export My Data" -msgstr "" +msgstr "Exporta les meves dades" #: src/view/com/modals/EmbedConsent.tsx:64 msgid "External Media" @@ -1484,7 +1489,7 @@ msgstr "Contingut extern" msgid "External media may allow websites to collect information about you and your device. No information is sent or requested until you press the \"play\" button." msgstr "El contingut extern pot permetre que algunes webs recullin informació sobre tu i el teu dispositiu. No s'envia ni es demana cap informació fins que premis el botó \"reproduir\"." -#: src/Navigation.tsx:261 +#: src/Navigation.tsx:263 #: src/view/screens/PreferencesExternalEmbeds.tsx:52 #: src/view/screens/Settings/index.tsx:657 msgid "External Media Preferences" @@ -1503,7 +1508,7 @@ msgstr "No s'ha pogut crear la contrasenya d'aplicació" msgid "Failed to create the list. Check your internet connection and try again." msgstr "No s'ha pogut crear la llista. Comprova la teva connexió a internet i torna-ho a provar." -#: src/view/com/util/forms/PostDropdownBtn.tsx:110 +#: src/view/com/util/forms/PostDropdownBtn.tsx:128 msgid "Failed to delete post, please try again" msgstr "No s'ha pogut esborrar la publicació, torna-ho a provar" @@ -1512,7 +1517,7 @@ msgstr "No s'ha pogut esborrar la publicació, torna-ho a provar" msgid "Failed to load recommended feeds" msgstr "Error en carregar els canals recomanats" -#: src/Navigation.tsx:192 +#: src/Navigation.tsx:194 msgid "Feed" msgstr "Canal" @@ -1533,7 +1538,7 @@ msgstr "Canal fora de lÃnia" msgid "Feedback" msgstr "Comentaris" -#: src/Navigation.tsx:445 +#: src/Navigation.tsx:452 #: src/view/screens/Feeds.tsx:419 #: src/view/screens/Feeds.tsx:524 #: src/view/screens/Profile.tsx:184 @@ -1554,11 +1559,11 @@ msgstr "Els canals són algoritmes personalitzats creats per usuaris que coneixe #: src/screens/Onboarding/StepTopicalFeeds.tsx:76 msgid "Feeds can be topical as well!" -msgstr "" +msgstr "Els canals també poden ser d'actualitat!" #: src/screens/Onboarding/StepFinished.tsx:151 msgid "Finalizing" -msgstr "" +msgstr "Finalitzant" #: src/view/com/posts/CustomFeedEmptyState.tsx:47 #: src/view/com/posts/FollowingEmptyState.tsx:57 @@ -1592,11 +1597,11 @@ msgstr "Ajusta els fils de debat." #: src/screens/Onboarding/index.tsx:38 msgid "Fitness" -msgstr "" +msgstr "Exercici" #: src/screens/Onboarding/StepFinished.tsx:131 msgid "Flexible" -msgstr "" +msgstr "Flexible" #: src/view/com/modals/EditImage.tsx:115 msgid "Flip horizontal" @@ -1626,11 +1631,11 @@ msgstr "Segueix {0}" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:179 msgid "Follow All" -msgstr "" +msgstr "Segueix-los a tots" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:174 msgid "Follow selected accounts and continue to the next step" -msgstr "" +msgstr "Segueix els comptes seleccionats i continua" #: src/view/com/auth/onboarding/RecommendedFollows.tsx:64 msgid "Follow some users to get started. We can recommend you more users based on who you find interesting." @@ -1670,9 +1675,9 @@ msgstr "Seguint" msgid "Following {0}" msgstr "Seguint {0}" -#: src/Navigation.tsx:248 -#: src/view/com/home/HomeHeaderLayout.web.tsx:45 -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:83 +#: src/Navigation.tsx:250 +#: src/view/com/home/HomeHeaderLayout.web.tsx:50 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:84 #: src/view/screens/PreferencesFollowingFeed.tsx:104 #: src/view/screens/Settings/index.tsx:543 msgid "Following Feed Preferences" @@ -1688,7 +1693,7 @@ msgstr "Et segueix" #: src/screens/Onboarding/index.tsx:43 msgid "Food" -msgstr "" +msgstr "Menjar" #: src/view/com/modals/DeleteAccount.tsx:111 msgid "For security reasons, we'll need to send a confirmation code to your email address." @@ -1711,6 +1716,11 @@ msgstr "He oblidat la contrasenya" msgid "Forgot Password" msgstr "He oblidat la contrasenya" +#: src/screens/Hashtag.tsx:108 +#: src/screens/Hashtag.tsx:148 +msgid "From @{sanitizedAuthor}" +msgstr "" + #: src/view/com/posts/FeedItem.tsx:189 msgctxt "from-feed" msgid "From <0/>" @@ -1734,15 +1744,15 @@ msgstr "Ves enrere" #: src/view/screens/ProfileFeed.tsx:106 #: src/view/screens/ProfileFeed.tsx:111 -#: src/view/screens/ProfileList.tsx:897 #: src/view/screens/ProfileList.tsx:902 +#: src/view/screens/ProfileList.tsx:907 msgid "Go Back" msgstr "Ves enrere" #: src/screens/Onboarding/Layout.tsx:104 #: src/screens/Onboarding/Layout.tsx:193 msgid "Go back to previous step" -msgstr "" +msgstr "Ves al pas anterior" #: src/view/screens/Search/Search.tsx:747 #: src/view/shell/desktop/Search.tsx:262 @@ -1761,8 +1771,16 @@ msgstr "Ves al següent" msgid "Handle" msgstr "Identificador" +#: src/Navigation.tsx:270 +msgid "Hashtag" +msgstr "" + #: src/components/RichText.tsx:188 -msgid "Hashtag: {tag}" +#~ msgid "Hashtag: {tag}" +#~ msgstr "" + +#: src/components/RichText.tsx:190 +msgid "Hashtag: #{tag}" msgstr "" #: src/view/com/auth/create/CreateAccount.tsx:208 @@ -1776,15 +1794,15 @@ msgstr "Ajuda" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:132 msgid "Here are some accounts for you to follow" -msgstr "" +msgstr "Aquà tens uns quants comptes que pots seguir" #: src/screens/Onboarding/StepTopicalFeeds.tsx:85 msgid "Here are some popular topical feeds. You can choose to follow as many as you like." -msgstr "" +msgstr "Aquà tens alguns canals d'actualitat populars. Pots seguir-ne tants com vulguis." #: src/screens/Onboarding/StepTopicalFeeds.tsx:80 msgid "Here are some topical feeds based on your interests: {interestsText}. You can choose to follow as many as you like." -msgstr "" +msgstr "Aquà tens uns quants canals d'actualitat basats en els teus interesos: {interestsText}. Pots seguir-ne tants com vulguis." #: src/view/com/modals/AddAppPasswords.tsx:153 msgid "Here is your app password." @@ -1798,12 +1816,13 @@ msgid "Hide" msgstr "Amaga" #: src/view/com/modals/ContentFilteringSettings.tsx:224 -#: src/view/com/notifications/FeedItem.tsx:325 +#: src/view/com/notifications/FeedItem.tsx:326 msgctxt "action" msgid "Hide" msgstr "Amaga" -#: src/view/com/util/forms/PostDropdownBtn.tsx:232 +#: src/view/com/util/forms/PostDropdownBtn.tsx:276 +#: src/view/com/util/forms/PostDropdownBtn.tsx:287 msgid "Hide post" msgstr "Amaga l'entrada" @@ -1812,11 +1831,11 @@ msgstr "Amaga l'entrada" msgid "Hide the content" msgstr "Amaga el contingut" -#: src/view/com/util/forms/PostDropdownBtn.tsx:236 +#: src/view/com/util/forms/PostDropdownBtn.tsx:280 msgid "Hide this post?" msgstr "Vols amagar aquesta entrada?" -#: src/view/com/notifications/FeedItem.tsx:315 +#: src/view/com/notifications/FeedItem.tsx:316 msgid "Hide user list" msgstr "Amaga la llista d'usuaris" @@ -1844,7 +1863,7 @@ msgstr "El servidor del canal ha donat una resposta incorrecta. Avisa al propiet msgid "Hmm, we're having trouble finding this feed. It may have been deleted." msgstr "Tenim problemes per trobar aquest canal. Potser ha estat eliminat." -#: src/Navigation.tsx:435 +#: src/Navigation.tsx:442 #: src/view/shell/bottom-bar/BottomBar.tsx:137 #: src/view/shell/desktop/LeftNav.tsx:306 #: src/view/shell/Drawer.tsx:398 @@ -1859,7 +1878,7 @@ msgstr "Inici" #~ msgid "Home Feed Preferences" #~ msgstr "Preferències dels canals a l'inici" -#: src/view/com/auth/create/Step1.tsx:82 +#: src/view/com/auth/create/Step1.tsx:75 #: src/view/com/auth/login/ForgotPasswordForm.tsx:120 msgid "Hosting provider" msgstr "Proveïdor d'allotjament" @@ -1895,7 +1914,7 @@ msgstr "Si no en selecciones cap, és apropiat per a totes les edats." #: src/view/com/modals/ChangePassword.tsx:146 msgid "If you want to change your password, we will send you a code to verify that this is your account." -msgstr "" +msgstr "Si vols canviar la contrasenya t'enviarem un codi per verificar que aquest compte és teu." #: src/view/com/util/images/Gallery.tsx:38 msgid "Image" @@ -1918,11 +1937,11 @@ msgstr "Introdueix el codi que s'ha enviat al teu correu per restablir la contra msgid "Input confirmation code for account deletion" msgstr "Introdueix el codi de confirmació per eliminar el compte" -#: src/view/com/auth/create/Step1.tsx:200 +#: src/view/com/auth/create/Step1.tsx:177 msgid "Input email for Bluesky account" msgstr "Introdueix el correu del compte de Bluesky" -#: src/view/com/auth/create/Step1.tsx:158 +#: src/view/com/auth/create/Step1.tsx:151 msgid "Input invite code to proceed" msgstr "Introdueix el codi d'invitació per continuar" @@ -1955,8 +1974,8 @@ msgstr "Introdueix el nom d'usuari o correu que vas utilitzar per registrar-te" #~ msgstr "Introdueix el codi de verificació que t'hem enviat" #: src/view/com/modals/Waitlist.tsx:90 -msgid "Input your email to get on the Bluesky waitlist" -msgstr "Introdueix el teu correu per afegir-te a la llista d'espera de Bluesky" +#~ msgid "Input your email to get on the Bluesky waitlist" +#~ msgstr "Introdueix el teu correu per afegir-te a la llista d'espera de Bluesky" #: src/view/com/auth/login/LoginForm.tsx:229 msgid "Input your password" @@ -1982,8 +2001,8 @@ msgstr "Nom d'usuari o contrasenya incorrectes" msgid "Invite a Friend" msgstr "Convida un amic" -#: src/view/com/auth/create/Step1.tsx:148 -#: src/view/com/auth/create/Step1.tsx:157 +#: src/view/com/auth/create/Step1.tsx:141 +#: src/view/com/auth/create/Step1.tsx:150 msgid "Invite code" msgstr "Codi d'invitació" @@ -2005,7 +2024,7 @@ msgstr "Codis d'invitació: 1 disponible" #: src/screens/Onboarding/StepFollowingFeed.tsx:64 msgid "It shows posts from the people you follow as they happen." -msgstr "" +msgstr "Mostra les publicacions de les persones que segueixes cronològicament." #: src/view/com/auth/HomeLoggedOutCTA.tsx:99 #: src/view/com/auth/SplashScreen.web.tsx:138 @@ -2013,21 +2032,21 @@ msgid "Jobs" msgstr "Feines" #: src/view/com/modals/Waitlist.tsx:67 -msgid "Join the waitlist" -msgstr "Uneix-te a la llista d'espera" +#~ msgid "Join the waitlist" +#~ msgstr "Uneix-te a la llista d'espera" #: src/view/com/auth/create/Step1.tsx:174 #: src/view/com/auth/create/Step1.tsx:178 -msgid "Join the waitlist." -msgstr "Uneix-te a la llista d'espera." +#~ msgid "Join the waitlist." +#~ msgstr "Uneix-te a la llista d'espera." #: src/view/com/modals/Waitlist.tsx:128 -msgid "Join Waitlist" -msgstr "Uneix-te a la llista d'espera" +#~ msgid "Join Waitlist" +#~ msgstr "Uneix-te a la llista d'espera" #: src/screens/Onboarding/index.tsx:24 msgid "Journalism" -msgstr "" +msgstr "Periodisme" #: src/view/com/composer/select-language/SelectLangBtn.tsx:104 msgid "Language selection" @@ -2037,7 +2056,7 @@ msgstr "Tria l'idioma" msgid "Language settings" msgstr "Configuració d'idioma" -#: src/Navigation.tsx:140 +#: src/Navigation.tsx:142 #: src/view/screens/LanguageSettings.tsx:89 msgid "Language Settings" msgstr "Configuració d'idioma" @@ -2082,7 +2101,7 @@ msgstr "Sortint de Bluesky" #: src/screens/Deactivated.tsx:128 msgid "left to go." -msgstr "" +msgstr "queda." #: src/view/screens/Settings/index.tsx:278 msgid "Legacy storage cleared, you need to restart the app now." @@ -2095,7 +2114,7 @@ msgstr "Restablirem la teva contrasenya!" #: src/screens/Onboarding/StepFinished.tsx:151 msgid "Let's go!" -msgstr "" +msgstr "Som-hi!" #: src/view/com/util/UserAvatar.tsx:248 #: src/view/com/util/UserBanner.tsx:62 @@ -2107,7 +2126,6 @@ msgid "Light" msgstr "Clar" #: src/view/com/util/post-ctrls/PostCtrls.tsx:182 -#: src/view/com/util/post-ctrls/PostCtrls.tsx:216 msgid "Like" msgstr "M'agrada" @@ -2115,14 +2133,14 @@ msgstr "M'agrada" msgid "Like this feed" msgstr "Fes m'agrada a aquest canal" -#: src/Navigation.tsx:197 +#: src/Navigation.tsx:199 msgid "Liked by" msgstr "Li ha agradat a" #: src/view/screens/PostLikedBy.tsx:27 #: src/view/screens/ProfileFeedLikedBy.tsx:27 msgid "Liked By" -msgstr "" +msgstr "Li ha agradat a" #: src/view/com/feeds/FeedSourceCard.tsx:279 msgid "Liked by {0} {1}" @@ -2134,7 +2152,7 @@ msgstr "Li ha agradat a {likeCount} {0}" #: src/view/com/notifications/FeedItem.tsx:170 msgid "liked your custom feed" -msgstr "" +msgstr "els hi ha agradat el teu canal personalitzat" #: src/view/com/notifications/FeedItem.tsx:171 #~ msgid "liked your custom feed{0}" @@ -2152,7 +2170,7 @@ msgstr "M'agrades" msgid "Likes on this post" msgstr "M'agrades a aquesta publicació" -#: src/Navigation.tsx:166 +#: src/Navigation.tsx:168 msgid "List" msgstr "Llista" @@ -2188,7 +2206,7 @@ msgstr "Llista desbloquejada" msgid "List unmuted" msgstr "Llista no silenciada" -#: src/Navigation.tsx:110 +#: src/Navigation.tsx:112 #: src/view/screens/Profile.tsx:185 #: src/view/shell/desktop/LeftNav.tsx:379 #: src/view/shell/Drawer.tsx:492 @@ -2220,7 +2238,7 @@ msgstr "Carregant…" #~ msgid "Local dev server" #~ msgstr "Servidor de desenvolupament local" -#: src/Navigation.tsx:207 +#: src/Navigation.tsx:209 msgid "Log" msgstr "Registre" @@ -2229,7 +2247,7 @@ msgstr "Registre" #: src/screens/Deactivated.tsx:178 #: src/screens/Deactivated.tsx:181 msgid "Log out" -msgstr "" +msgstr "Desconnecta" #: src/view/screens/Moderation.tsx:155 msgid "Logged-out visibility" @@ -2246,7 +2264,7 @@ msgstr "Accedeix a un compte que no està llistat" msgid "Make sure this is where you intend to go!" msgstr "Assegura't que és aquà on vols anar!" -#: src/components/dialogs/MutedWords.tsx:71 +#: src/components/dialogs/MutedWords.tsx:83 msgid "Manage your muted words and tags" msgstr "" @@ -2270,7 +2288,7 @@ msgstr "usuaris mencionats" msgid "Mentioned users" msgstr "Usuaris mencionats" -#: src/view/com/util/ViewHeader.tsx:81 +#: src/view/com/util/ViewHeader.tsx:87 #: src/view/screens/Search/Search.tsx:646 msgid "Menu" msgstr "Menú" @@ -2283,7 +2301,7 @@ msgstr "Menú" msgid "Message from server: {0}" msgstr "Missatge del servidor: {0}" -#: src/Navigation.tsx:115 +#: src/Navigation.tsx:117 #: src/view/screens/Moderation.tsx:66 #: src/view/screens/Settings/index.tsx:625 #: src/view/shell/desktop/LeftNav.tsx:397 @@ -2297,13 +2315,13 @@ msgstr "Moderació" msgid "Moderation list by {0}" msgstr "Llista de moderació per {0}" -#: src/view/screens/ProfileList.tsx:774 +#: src/view/screens/ProfileList.tsx:775 msgid "Moderation list by <0/>" msgstr "Llista de moderació per <0/>" #: src/view/com/lists/ListCard.tsx:91 #: src/view/com/modals/UserAddRemoveLists.tsx:204 -#: src/view/screens/ProfileList.tsx:772 +#: src/view/screens/ProfileList.tsx:773 msgid "Moderation list by you" msgstr "Llista de moderació teva" @@ -2319,7 +2337,7 @@ msgstr "S'ha actualitzat la llista de moderació" msgid "Moderation lists" msgstr "Llistes de moderació" -#: src/Navigation.tsx:120 +#: src/Navigation.tsx:122 #: src/view/screens/ModerationModlists.tsx:58 msgid "Moderation Lists" msgstr "Llistes de moderació" @@ -2332,7 +2350,7 @@ msgstr "Configuració de moderació" msgid "Moderator has chosen to set a general warning on the content." msgstr "El moderador ha decidit establir un advertiment general sobre el contingut" -#: src/view/shell/desktop/Feeds.tsx:63 +#: src/view/shell/desktop/Feeds.tsx:65 msgid "More feeds" msgstr "Més canals" @@ -2343,8 +2361,8 @@ msgid "More options" msgstr "Més opcions" #: src/view/com/util/forms/PostDropdownBtn.tsx:315 -msgid "More post options" -msgstr "Més opcions de publicació" +#~ msgid "More post options" +#~ msgstr "Més opcions de publicació" #: src/view/screens/PreferencesThreads.tsx:82 msgid "Most-liked replies first" @@ -2354,11 +2372,11 @@ msgstr "Respostes amb més m'agrada primer" msgid "Must be at least 3 characters" msgstr "" -#: src/components/TagMenu/index.tsx:253 +#: src/components/TagMenu/index.tsx:249 msgid "Mute" msgstr "" -#: src/components/TagMenu/index.web.tsx:91 +#: src/components/TagMenu/index.web.tsx:105 msgid "Mute {truncatedTag}" msgstr "" @@ -2370,15 +2388,19 @@ msgstr "Silenciar el compte" msgid "Mute accounts" msgstr "Silencia els comptes" -#: src/components/TagMenu/index.tsx:211 -msgid "Mute all {tag} posts" +#: src/components/TagMenu/index.tsx:209 +msgid "Mute all {displayTag} posts" msgstr "" -#: src/components/dialogs/MutedWords.tsx:131 +#: src/components/TagMenu/index.tsx:211 +#~ msgid "Mute all {tag} posts" +#~ msgstr "" + +#: src/components/dialogs/MutedWords.tsx:149 msgid "Mute in tags only" msgstr "" -#: src/components/dialogs/MutedWords.tsx:116 +#: src/components/dialogs/MutedWords.tsx:134 msgid "Mute in text & tags" msgstr "" @@ -2394,19 +2416,21 @@ msgstr "Vols silenciar aquests comptes?" msgid "Mute this List" msgstr "Silencia aquesta llista" -#: src/components/dialogs/MutedWords.tsx:109 +#: src/components/dialogs/MutedWords.tsx:127 msgid "Mute this word in post text and tags" msgstr "" -#: src/components/dialogs/MutedWords.tsx:124 +#: src/components/dialogs/MutedWords.tsx:142 msgid "Mute this word in tags only" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:202 +#: src/view/com/util/forms/PostDropdownBtn.tsx:251 +#: src/view/com/util/forms/PostDropdownBtn.tsx:257 msgid "Mute thread" msgstr "Silencia el fil de debat" -#: src/view/com/util/forms/PostDropdownBtn.tsx:216 +#: src/view/com/util/forms/PostDropdownBtn.tsx:267 +#: src/view/com/util/forms/PostDropdownBtn.tsx:269 msgid "Mute words & tags" msgstr "" @@ -2418,7 +2442,7 @@ msgstr "Silenciada" msgid "Muted accounts" msgstr "Comptes silenciats" -#: src/Navigation.tsx:125 +#: src/Navigation.tsx:127 #: src/view/screens/ModerationMutedAccounts.tsx:107 msgid "Muted Accounts" msgstr "Comptes silenciats" @@ -2453,7 +2477,7 @@ msgstr "Els meus canals desats" #: src/view/com/auth/server-input/index.tsx:118 msgid "my-server.com" -msgstr "" +msgstr "el-meu-servidor.com" #: src/view/com/modals/AddAppPasswords.tsx:179 #: src/view/com/modals/CreateOrEditList.tsx:290 @@ -2466,7 +2490,7 @@ msgstr "Es requereix un nom" #: src/screens/Onboarding/index.tsx:25 msgid "Nature" -msgstr "" +msgstr "Natura" #: src/view/com/auth/login/ForgotPasswordForm.tsx:190 #: src/view/com/auth/login/ForgotPasswordForm.tsx:219 @@ -2492,9 +2516,9 @@ msgstr "No perdis mai accés als teus seguidors ni a les teves dades." #: src/screens/Onboarding/StepFinished.tsx:119 msgid "Never lose access to your followers or data." -msgstr "" +msgstr "No perdis mai accés als teus seguidors i les teves dades." -#: src/components/dialogs/MutedWords.tsx:244 +#: src/components/dialogs/MutedWords.tsx:293 msgid "Nevermind" msgstr "" @@ -2517,7 +2541,7 @@ msgstr "Nova contrasenya" #: src/view/com/modals/ChangePassword.tsx:215 msgid "New Password" -msgstr "" +msgstr "Nova contrasenya" #: src/view/com/feeds/FeedPage.tsx:126 msgctxt "action" @@ -2553,7 +2577,7 @@ msgstr "Les respostes més noves primer" #: src/screens/Onboarding/index.tsx:23 msgid "News" -msgstr "" +msgstr "NotÃcies" #: src/view/com/auth/create/CreateAccount.tsx:172 #: src/view/com/auth/login/ForgotPasswordForm.tsx:182 @@ -2586,7 +2610,7 @@ msgid "No" msgstr "No" #: src/view/screens/ProfileFeed.tsx:584 -#: src/view/screens/ProfileList.tsx:754 +#: src/view/screens/ProfileList.tsx:755 msgid "No description" msgstr "Cap descripció" @@ -2603,6 +2627,10 @@ msgstr "Encara no tens cap notificació" msgid "No result" msgstr "Cap resultat" +#: src/components/Lists.tsx:192 +msgid "No results found" +msgstr "" + #: src/view/screens/Feeds.tsx:495 msgid "No results found for \"{query}\"" msgstr "No s'han trobat resultats per \"{query}\"" @@ -2625,7 +2653,7 @@ msgstr "Ningú" msgid "Not Applicable." msgstr "No aplicable." -#: src/Navigation.tsx:105 +#: src/Navigation.tsx:107 #: src/view/screens/Profile.tsx:106 msgid "Not Found" msgstr "No s'ha trobat" @@ -2639,7 +2667,7 @@ msgstr "Ara mateix no" msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites." msgstr "Nota: Bluesky és una xarxa oberta i pública. Aquesta configuració tan sols limita el teu contingut a l'aplicació de Bluesky i a la web, altres aplicacions poden no respectar-ho. El teu contingut pot ser mostrat a usuaris no connectats per altres aplicacions i webs." -#: src/Navigation.tsx:450 +#: src/Navigation.tsx:457 #: src/view/screens/Notifications.tsx:124 #: src/view/screens/Notifications.tsx:148 #: src/view/shell/bottom-bar/BottomBar.tsx:205 @@ -2659,7 +2687,7 @@ msgstr "Ostres!" #: src/screens/Onboarding/StepInterests/index.tsx:128 msgid "Oh no! Something went wrong." -msgstr "" +msgstr "Ostres! Alguna cosa ha fallat." #: src/view/com/auth/login/PasswordUpdatedForm.tsx:41 msgid "Okay" @@ -2681,6 +2709,11 @@ msgstr "Falta el text alternatiu a una o més imatges." msgid "Only {0} can reply." msgstr "Només {0} poden respondre." +#: src/components/Lists.tsx:82 +msgid "Oops, something went wrong!" +msgstr "" + +#: src/components/Lists.tsx:188 #: src/view/screens/AppPasswords.tsx:65 #: src/view/screens/Profile.tsx:106 msgid "Oops!" @@ -2688,7 +2721,7 @@ msgstr "Ostres!" #: src/screens/Onboarding/StepFinished.tsx:115 msgid "Open" -msgstr "" +msgstr "Obre" #: src/view/screens/Moderation.tsx:75 msgid "Open content filtering settings" @@ -2707,13 +2740,17 @@ msgstr "Obre els enllaços al navegador de l'aplicació" msgid "Open muted words settings" msgstr "" -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:49 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:50 msgid "Open navigation" msgstr "Obre la navegació" +#: src/view/com/util/forms/PostDropdownBtn.tsx:175 +msgid "Open post options menu" +msgstr "" + #: src/view/screens/Settings/index.tsx:804 msgid "Open storybook page" -msgstr "" +msgstr "Obre la pà gina d'historial" #: src/view/com/util/forms/DropdownButton.tsx:154 msgid "Opens {numItems} options" @@ -2723,7 +2760,7 @@ msgstr "Obre {numItems} opcions" msgid "Opens additional details for a debug entry" msgstr "Obre detalls adicionals per una entrada de depuració" -#: src/view/com/notifications/FeedItem.tsx:348 +#: src/view/com/notifications/FeedItem.tsx:349 msgid "Opens an expanded list of users in this notification" msgstr "Obre una llista expandida d'usuaris en aquesta notificació" @@ -2783,7 +2820,7 @@ msgstr "Obre la configuració de la moderació" msgid "Opens password reset form" msgstr "Obre el formulari de restabliment de la contrasenya" -#: src/view/com/home/HomeHeaderLayout.web.tsx:60 +#: src/view/com/home/HomeHeaderLayout.web.tsx:63 #: src/view/screens/Feeds.tsx:356 msgid "Opens screen to edit Saved Feeds" msgstr "Obre pantalla per editar els canals desats" @@ -2832,16 +2869,17 @@ msgstr "Un altre compte" msgid "Other..." msgstr "Un altre…" +#: src/components/Lists.tsx:194 #: src/view/screens/NotFound.tsx:45 msgid "Page not found" msgstr "Pà gina no trobada" #: src/view/screens/NotFound.tsx:42 msgid "Page Not Found" -msgstr "" +msgstr "Pà gina no trobada" -#: src/view/com/auth/create/Step1.tsx:214 -#: src/view/com/auth/create/Step1.tsx:224 +#: src/view/com/auth/create/Step1.tsx:191 +#: src/view/com/auth/create/Step1.tsx:201 #: src/view/com/auth/login/LoginForm.tsx:226 #: src/view/com/auth/login/SetNewPasswordForm.tsx:161 #: src/view/com/modals/DeleteAccount.tsx:202 @@ -2856,11 +2894,11 @@ msgstr "Contrasenya actualitzada" msgid "Password updated!" msgstr "Contrasenya actualitzada!" -#: src/Navigation.tsx:160 +#: src/Navigation.tsx:162 msgid "People followed by @{0}" msgstr "Persones seguides per @{0}" -#: src/Navigation.tsx:153 +#: src/Navigation.tsx:155 msgid "People following @{0}" msgstr "Persones seguint a @{0}" @@ -2874,7 +2912,7 @@ msgstr "S'ha denegat el permÃs per accedir a la cà mera. Activa'l a la configur #: src/screens/Onboarding/index.tsx:31 msgid "Pets" -msgstr "" +msgstr "Mascotes" #: src/view/com/auth/create/Step2.tsx:183 #~ msgid "Phone number" @@ -2934,6 +2972,10 @@ msgstr "Introdueix un nom per a la contrasenya de la vostra aplicació. No es pe msgid "Please enter a unique name for this App Password or use our randomly generated one." msgstr "Introdueix un nom únic per aquesta contrasenya d'aplicació o fes servir un nom generat aleatòriament." +#: src/components/dialogs/MutedWords.tsx:68 +msgid "Please enter a valid word, tag, or phrase to mute" +msgstr "" + #: src/view/com/auth/create/state.ts:170 #~ msgid "Please enter the code you received by SMS." #~ msgstr "Introdueix el codi que has rebut per SMS" @@ -2968,7 +3010,7 @@ msgstr "Espera que es generi la targeta de l'enllaç" #: src/screens/Onboarding/index.tsx:37 msgid "Politics" -msgstr "" +msgstr "PolÃtica" #: src/view/com/modals/SelfLabel.tsx:111 msgid "Porn" @@ -2995,13 +3037,13 @@ msgstr "Publicació" msgid "Post by {0}" msgstr "Publicació per {0}" -#: src/Navigation.tsx:172 -#: src/Navigation.tsx:179 -#: src/Navigation.tsx:186 +#: src/Navigation.tsx:174 +#: src/Navigation.tsx:181 +#: src/Navigation.tsx:188 msgid "Post by @{0}" msgstr "Publicació per @{0}" -#: src/view/com/util/forms/PostDropdownBtn.tsx:90 +#: src/view/com/util/forms/PostDropdownBtn.tsx:108 msgid "Post deleted" msgstr "Publicació eliminada" @@ -3021,7 +3063,7 @@ msgstr "Idiomes de les publicacions" msgid "Post not found" msgstr "Publicació no trobada" -#: src/components/TagMenu/index.tsx:257 +#: src/components/TagMenu/index.tsx:253 msgid "posts" msgstr "" @@ -3029,7 +3071,7 @@ msgstr "" msgid "Posts" msgstr "Publicacions" -#: src/components/dialogs/MutedWords.tsx:77 +#: src/components/dialogs/MutedWords.tsx:90 msgid "Posts can be muted based on their text, their tags, or both." msgstr "" @@ -3058,7 +3100,7 @@ msgstr "Prioritza els usuaris que segueixes" msgid "Privacy" msgstr "Privacitat" -#: src/Navigation.tsx:217 +#: src/Navigation.tsx:219 #: src/view/screens/PrivacyPolicy.tsx:29 #: src/view/screens/Settings/index.tsx:891 #: src/view/shell/Drawer.tsx:262 @@ -3087,7 +3129,7 @@ msgstr "Protegeix el teu compte verificant el teu correu." #: src/screens/Onboarding/StepFinished.tsx:101 msgid "Public" -msgstr "" +msgstr "Públic" #: src/view/screens/ModerationModlists.tsx:61 msgid "Public, shareable lists of users to mute or block in bulk." @@ -3139,7 +3181,7 @@ msgstr "Canals recomanats" msgid "Recommended Users" msgstr "Usuaris recomanats" -#: src/components/dialogs/MutedWords.tsx:249 +#: src/components/dialogs/MutedWords.tsx:298 #: src/view/com/modals/ListAddRemoveUsers.tsx:264 #: src/view/com/modals/SelfLabel.tsx:83 #: src/view/com/modals/UserAddRemoveLists.tsx:219 @@ -3177,7 +3219,7 @@ msgstr "Elimina la imatge" msgid "Remove image preview" msgstr "Elimina la visualització prèvia de la imatge" -#: src/components/dialogs/MutedWords.tsx:294 +#: src/components/dialogs/MutedWords.tsx:343 msgid "Remove mute word from your list" msgstr "" @@ -3247,7 +3289,8 @@ msgid "Report List" msgstr "Informa de la llista" #: src/view/com/modals/report/SendReportButton.tsx:37 -#: src/view/com/util/forms/PostDropdownBtn.tsx:255 +#: src/view/com/util/forms/PostDropdownBtn.tsx:301 +#: src/view/com/util/forms/PostDropdownBtn.tsx:309 msgid "Report post" msgstr "Informa de la publicació" @@ -3257,7 +3300,7 @@ msgstr "Informa de la publicació" #: src/view/com/util/post-ctrls/RepostButton.tsx:61 msgctxt "action" msgid "Repost" -msgstr "Respon" +msgstr "Republica" #: src/view/com/util/post-ctrls/RepostButton.web.tsx:48 msgid "Repost" @@ -3274,11 +3317,11 @@ msgstr "Republica o cita la publicació" #: src/view/screens/PostRepostedBy.tsx:27 msgid "Reposted By" -msgstr "" +msgstr "Republicat per" #: src/view/com/posts/FeedItem.tsx:207 msgid "Reposted by {0}" -msgstr "" +msgstr "Republicat per {0}" #: src/view/com/posts/FeedItem.tsx:206 #~ msgid "Reposted by {0})" @@ -3308,13 +3351,13 @@ msgstr "Demana un canvi" #: src/view/com/modals/ChangePassword.tsx:239 #: src/view/com/modals/ChangePassword.tsx:241 msgid "Request Code" -msgstr "" +msgstr "Demana un codi" #: src/view/screens/Settings/index.tsx:456 msgid "Require alt text before posting" msgstr "Requereix un text alternatiu abans de publicar" -#: src/view/com/auth/create/Step1.tsx:153 +#: src/view/com/auth/create/Step1.tsx:146 msgid "Required for this provider" msgstr "Requerit per aquest proveïdor" @@ -3325,7 +3368,7 @@ msgstr "Codi de restabliment" #: src/view/com/modals/ChangePassword.tsx:190 msgid "Reset Code" -msgstr "" +msgstr "Codi de restabliment" #: src/view/screens/Settings/index.tsx:824 msgid "Reset onboarding" @@ -3379,7 +3422,7 @@ msgstr "Torna-ho a provar" #~ msgid "Retry." #~ msgstr "Torna-ho a provar" -#: src/view/screens/ProfileList.tsx:898 +#: src/view/screens/ProfileList.tsx:903 msgid "Return to previous page" msgstr "Torna a la pà gina anterior" @@ -3432,13 +3475,13 @@ msgstr "Desa el canvi d'identificador a {handle}" #: src/screens/Onboarding/index.tsx:36 msgid "Science" -msgstr "" +msgstr "Ciència" -#: src/view/screens/ProfileList.tsx:854 +#: src/view/screens/ProfileList.tsx:859 msgid "Scroll to top" msgstr "Desplaça't cap a dalt" -#: src/Navigation.tsx:440 +#: src/Navigation.tsx:447 #: src/view/com/auth/LoggedOut.tsx:122 #: src/view/com/modals/ListAddRemoveUsers.tsx:75 #: src/view/com/util/forms/SearchInput.tsx:67 @@ -3461,13 +3504,21 @@ msgid "Search for \"{query}\"" msgstr "Cerca per \"{query}\"" #: src/components/TagMenu/index.tsx:145 -msgid "Search for all posts by @{authorHandle} with tag {tag}" +msgid "Search for all posts by @{authorHandle} with tag {displayTag}" msgstr "" -#: src/components/TagMenu/index.tsx:90 -msgid "Search for all posts with tag {tag}" +#: src/components/TagMenu/index.tsx:145 +#~ msgid "Search for all posts by @{authorHandle} with tag {tag}" +#~ msgstr "" + +#: src/components/TagMenu/index.tsx:94 +msgid "Search for all posts with tag {displayTag}" msgstr "" +#: src/components/TagMenu/index.tsx:90 +#~ msgid "Search for all posts with tag {tag}" +#~ msgstr "" + #: src/view/com/auth/LoggedOut.tsx:104 #: src/view/com/auth/LoggedOut.tsx:105 #: src/view/com/modals/ListAddRemoveUsers.tsx:70 @@ -3478,22 +3529,30 @@ msgstr "Cerca usuaris" msgid "Security Step Required" msgstr "Es requereix un pas de seguretat" -#: src/components/TagMenu/index.web.tsx:50 +#: src/components/TagMenu/index.web.tsx:66 msgid "See {truncatedTag} posts" msgstr "" -#: src/components/TagMenu/index.web.tsx:67 +#: src/components/TagMenu/index.web.tsx:83 msgid "See {truncatedTag} posts by user" msgstr "" #: src/components/TagMenu/index.tsx:128 -msgid "See <0>{tag}</0> posts" +msgid "See <0>{displayTag}</0> posts" msgstr "" -#: src/components/TagMenu/index.tsx:189 -msgid "See <0>{tag}</0> posts by this user" +#: src/components/TagMenu/index.tsx:187 +msgid "See <0>{displayTag}</0> posts by this user" msgstr "" +#: src/components/TagMenu/index.tsx:128 +#~ msgid "See <0>{tag}</0> posts" +#~ msgstr "" + +#: src/components/TagMenu/index.tsx:189 +#~ msgid "See <0>{tag}</0> posts by this user" +#~ msgstr "" + #: src/view/screens/SavedFeeds.tsx:163 msgid "See this guide" msgstr "Consulta aquesta guia" @@ -3518,26 +3577,26 @@ msgstr "Selecciona d'un compte existent" msgid "Select option {i} of {numItems}" msgstr "Selecciona l'opció {i} de {numItems}" -#: src/view/com/auth/create/Step1.tsx:103 +#: src/view/com/auth/create/Step1.tsx:96 #: src/view/com/auth/login/LoginForm.tsx:150 msgid "Select service" msgstr "Selecciona el servei" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:52 msgid "Select some accounts below to follow" -msgstr "" +msgstr "Selecciona alguns d'aquests comptes per seguir-los" #: src/view/com/auth/server-input/index.tsx:82 msgid "Select the service that hosts your data." -msgstr "" +msgstr "Selecciona el servei que allotja les teves dades." #: src/screens/Onboarding/StepTopicalFeeds.tsx:96 msgid "Select topical feeds to follow from the list below" -msgstr "" +msgstr "Selecciona els canals d'actualitat per seguir d'aquesta llista" #: src/screens/Onboarding/StepModeration/index.tsx:75 msgid "Select what you want to see (or not see), and we’ll handle the rest." -msgstr "" +msgstr "Selecciona què vols veure (o què no vols veure) i nosaltres farem la resta." #: src/view/screens/LanguageSettings.tsx:281 msgid "Select which languages you want your subscribed feeds to include. If none are selected, all languages will be shown." @@ -3549,7 +3608,7 @@ msgstr "Selecciona l'idioma de l'aplicació perquè el text predeterminat es mos #: src/screens/Onboarding/StepInterests/index.tsx:196 msgid "Select your interests from the options below" -msgstr "" +msgstr "Selecciona els teus interesos d'entre aquestes opcions" #: src/view/com/auth/create/Step2.tsx:155 #~ msgid "Select your phone's country" @@ -3561,11 +3620,11 @@ msgstr "Selecciona el teu idioma preferit per a les traduccions al teu canal." #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:116 msgid "Select your primary algorithmic feeds" -msgstr "" +msgstr "Selecciona els teus canals algorÃtmics primaris" #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:142 msgid "Select your secondary algorithmic feeds" -msgstr "" +msgstr "Selecciona els teus canals algorÃtmics secundaris" #: src/view/com/modals/VerifyEmail.tsx:202 #: src/view/com/modals/VerifyEmail.tsx:204 @@ -3600,7 +3659,7 @@ msgstr "Envia un correu amb el codi de confirmació per l'eliminació del compte #: src/view/com/auth/server-input/index.tsx:110 msgid "Server address" -msgstr "" +msgstr "Adreça del servidor" #: src/view/com/modals/ContentFilteringSettings.tsx:311 msgid "Set {value} for {labelGroup} content moderation policy" @@ -3626,17 +3685,17 @@ msgstr "Estableix el tema de colors a la configuració del sistema" #: src/view/screens/Settings/index.tsx:514 msgid "Set dark theme to the dark theme" -msgstr "" +msgstr "Posa el tema fosc" #: src/view/screens/Settings/index.tsx:507 msgid "Set dark theme to the dim theme" -msgstr "" +msgstr "Posa el tema fosc al tema atenuat" #: src/view/com/auth/login/SetNewPasswordForm.tsx:104 msgid "Set new password" msgstr "Estableix una nova contrasenya" -#: src/view/com/auth/create/Step1.tsx:225 +#: src/view/com/auth/create/Step1.tsx:202 msgid "Set password" msgstr "Estableix una contrasenya" @@ -3666,7 +3725,7 @@ msgstr "" #: src/screens/Onboarding/Layout.tsx:50 msgid "Set up your account" -msgstr "" +msgstr "Configura el teu compte" #: src/view/com/modals/ChangeHandle.tsx:266 msgid "Sets Bluesky username" @@ -3680,12 +3739,12 @@ msgstr "Estableix un correu per restablir la contrasenya" msgid "Sets hosting provider for password reset" msgstr "Estableix un proveïdor d'allotjament per restablir la contrasenya" -#: src/view/com/auth/create/Step1.tsx:104 +#: src/view/com/auth/create/Step1.tsx:97 #: src/view/com/auth/login/LoginForm.tsx:151 msgid "Sets server for the Bluesky client" msgstr "Estableix el servidor pel cient de Bluesky" -#: src/Navigation.tsx:135 +#: src/Navigation.tsx:137 #: src/view/screens/Settings/index.tsx:294 #: src/view/shell/desktop/LeftNav.tsx:433 #: src/view/shell/Drawer.tsx:567 @@ -3703,7 +3762,9 @@ msgid "Share" msgstr "Comparteix" #: src/view/com/profile/ProfileHeader.tsx:295 -#: src/view/com/util/forms/PostDropdownBtn.tsx:184 +#: src/view/com/util/forms/PostDropdownBtn.tsx:231 +#: src/view/com/util/forms/PostDropdownBtn.tsx:237 +#: src/view/com/util/post-ctrls/PostCtrls.tsx:215 #: src/view/screens/ProfileList.tsx:418 msgid "Share" msgstr "Comparteix" @@ -3752,15 +3813,15 @@ msgstr "Mostra les publicacions citades" #: src/screens/Onboarding/StepFollowingFeed.tsx:118 msgid "Show quote-posts in Following feed" -msgstr "" +msgstr "Mostra les publicacions citades en el canal Seguint" #: src/screens/Onboarding/StepFollowingFeed.tsx:134 msgid "Show quotes in Following" -msgstr "" +msgstr "Mostra els citats a Seguint" #: src/screens/Onboarding/StepFollowingFeed.tsx:94 msgid "Show re-posts in Following feed" -msgstr "" +msgstr "Mostra les republicacions al canal Seguint" #: src/view/screens/PreferencesFollowingFeed.tsx:119 msgid "Show Replies" @@ -3772,11 +3833,11 @@ msgstr "Mostra les respostes dels comptes que segueixes abans que les altres." #: src/screens/Onboarding/StepFollowingFeed.tsx:86 msgid "Show replies in Following" -msgstr "" +msgstr "Mostra les respostes a Seguint" #: src/screens/Onboarding/StepFollowingFeed.tsx:70 msgid "Show replies in Following feed" -msgstr "" +msgstr "Mostrea les respostes al canal Seguint" #: src/view/screens/PreferencesFollowingFeed.tsx:70 msgid "Show replies with at least {value} {0}" @@ -3788,14 +3849,14 @@ msgstr "Mostra republicacions" #: src/screens/Onboarding/StepFollowingFeed.tsx:110 msgid "Show reposts in Following" -msgstr "" +msgstr "Mostra les republicacions al canal Seguint" #: src/view/com/util/moderation/ContentHider.tsx:67 #: src/view/com/util/moderation/PostHider.tsx:61 msgid "Show the content" msgstr "Mostra el contingut" -#: src/view/com/notifications/FeedItem.tsx:346 +#: src/view/com/notifications/FeedItem.tsx:347 msgid "Show users" msgstr "Mostra usuaris" @@ -3888,7 +3949,7 @@ msgstr "Salta aquest pas" #: src/screens/Onboarding/StepInterests/index.tsx:232 msgid "Skip this flow" -msgstr "" +msgstr "Salta aquest flux" #: src/view/com/auth/create/Step2.tsx:82 #~ msgid "SMS verification" @@ -3896,17 +3957,21 @@ msgstr "" #: src/screens/Onboarding/index.tsx:40 msgid "Software Dev" -msgstr "" +msgstr "Desenvolupament de programari" #: src/view/com/modals/ProfilePreview.tsx:62 #~ msgid "Something went wrong and we're not sure what." #~ msgstr "Alguna cosa ha fallat i no estem segurs de què." +#: src/components/Lists.tsx:203 +msgid "Something went wrong!" +msgstr "" + #: src/view/com/modals/Waitlist.tsx:51 -msgid "Something went wrong. Check your email and try again." -msgstr "Alguna cosa ha fallat. Comprova el teu correu i torna-ho a provar." +#~ msgid "Something went wrong. Check your email and try again." +#~ msgstr "Alguna cosa ha fallat. Comprova el teu correu i torna-ho a provar." -#: src/App.native.tsx:63 +#: src/App.native.tsx:66 msgid "Sorry! Your session expired. Please log in again." msgstr "La teva sessió ha caducat. Torna a inciar-la." @@ -3920,7 +3985,7 @@ msgstr "Ordena les respostes a la mateixa publicació per:" #: src/screens/Onboarding/index.tsx:30 msgid "Sports" -msgstr "" +msgstr "Esports" #: src/view/com/modals/crop-image/CropImage.web.tsx:122 msgid "Square" @@ -3942,7 +4007,7 @@ msgstr "Pas {0} de {numSteps}" msgid "Storage cleared, you need to restart the app now." msgstr "L'emmagatzematge s'ha esborrat, cal que reinicieu l'aplicació ara." -#: src/Navigation.tsx:202 +#: src/Navigation.tsx:204 #: src/view/screens/Settings/index.tsx:807 msgid "Storybook" msgstr "Historial" @@ -3956,9 +4021,9 @@ msgid "Subscribe" msgstr "Subscriure's" #: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:173 -#: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:307 +#: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:308 msgid "Subscribe to the {0} feed" -msgstr "" +msgstr "Subscriu-te al canal {0}" #: src/view/screens/ProfileList.tsx:604 msgid "Subscribe to this list" @@ -3976,7 +4041,7 @@ msgstr "Suggeriments per tu" msgid "Suggestive" msgstr "Suggerent" -#: src/Navigation.tsx:212 +#: src/Navigation.tsx:214 #: src/view/screens/Support.tsx:30 #: src/view/screens/Support.tsx:33 msgid "Support" @@ -4008,14 +4073,18 @@ msgstr "Sistema" msgid "System log" msgstr "Registres del sistema" -#: src/components/dialogs/MutedWords.tsx:288 +#: src/components/dialogs/MutedWords.tsx:337 msgid "tag" msgstr "" -#: src/components/TagMenu/index.tsx:74 -msgid "Tag menu: {tag}" +#: src/components/TagMenu/index.tsx:78 +msgid "Tag menu: {displayTag}" msgstr "" +#: src/components/TagMenu/index.tsx:74 +#~ msgid "Tag menu: {tag}" +#~ msgstr "" + #: src/view/com/modals/crop-image/CropImage.web.tsx:112 msgid "Tall" msgstr "Alt" @@ -4026,20 +4095,20 @@ msgstr "Toca per veure-ho completament" #: src/screens/Onboarding/index.tsx:39 msgid "Tech" -msgstr "" +msgstr "Tecnologia" #: src/view/shell/desktop/RightNav.tsx:81 msgid "Terms" msgstr "Condicions" -#: src/Navigation.tsx:222 +#: src/Navigation.tsx:224 #: src/view/screens/Settings/index.tsx:885 #: src/view/screens/TermsOfService.tsx:29 #: src/view/shell/Drawer.tsx:256 msgid "Terms of Service" msgstr "Condicions del servei" -#: src/components/dialogs/MutedWords.tsx:288 +#: src/components/dialogs/MutedWords.tsx:337 msgid "text" msgstr "" @@ -4066,7 +4135,7 @@ msgstr "La polÃtica de drets d'autoria ha estat traslladada a <0/>" #: src/screens/Onboarding/Layout.tsx:60 msgid "The following steps will help customize your Bluesky experience." -msgstr "" +msgstr "Els següents passos t'ajudaran a personalitzar la teva experiència a Bluesky." #: src/view/com/post-thread/PostThread.tsx:517 msgid "The post may have been deleted." @@ -4090,7 +4159,7 @@ msgstr "Les condicions del servei han estat traslladades a " #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:150 msgid "There are many feeds to try:" -msgstr "" +msgstr "Hi ha molts canals per provar:" #: src/view/screens/ProfileFeed.tsx:550 msgid "There was an an issue contacting the server, please check your internet connection and try again." @@ -4124,7 +4193,7 @@ msgstr "Hi ha hagut un problema per contactar amb el teu servidor" msgid "There was an issue fetching notifications. Tap here to try again." msgstr "Hi ha hagut un problema en obtenir les notificacions. Toca aquà per tornar-ho a provar." -#: src/view/com/posts/Feed.tsx:263 +#: src/view/com/posts/Feed.tsx:265 msgid "There was an issue fetching posts. Tap here to try again." msgstr "Hi ha hagut un problema en obtenir les notificacions. Toca aquà per tornar-ho a provar." @@ -4170,7 +4239,7 @@ msgstr "S'ha produït un problema inesperat a l'aplicació. Fes-nos saber si aix #: src/screens/Deactivated.tsx:106 msgid "There's been a rush of new users to Bluesky! We'll activate your account as soon as we can." -msgstr "" +msgstr "Hi ha hagut una gran quantitat d'usuaris nous a Bluesky! Activarem el teu compte tan aviat com puguem." #: src/view/com/auth/create/Step2.tsx:55 #~ msgid "There's something wrong with this number. Please choose your country and enter your full phone number!" @@ -4178,7 +4247,7 @@ msgstr "" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:138 msgid "These are popular accounts you might like:" -msgstr "" +msgstr "Aquests són alguns comptes populars que et poden agradar:" #~ msgid "This {0} has been labeled." #~ msgstr "Aquest {0} ha estat etiquetat." @@ -4205,7 +4274,7 @@ msgstr "Aquest contingut no es pot veure sense un compte de Bluesky." #: src/view/screens/Settings/ExportCarDialog.tsx:75 msgid "This feature is in beta. You can read more about repository exports in <0>this blogpost.</0>" -msgstr "" +msgstr "Aquesta funcionalitat està en beta. En <0>aquesta entrada al blog</0> tens més informació." #: src/view/com/posts/FeedErrorMessage.tsx:114 msgid "This feed is currently receiving high traffic and is temporarily unavailable. Please try again later." @@ -4237,7 +4306,7 @@ msgstr "Això és important si mai necessites canviar el teu correu o restablir msgid "This link is taking you to the following website:" msgstr "Aquest enllaç et porta a la web:" -#: src/view/screens/ProfileList.tsx:834 +#: src/view/screens/ProfileList.tsx:839 msgid "This list is empty!" msgstr "Aquesta llista està buida!" @@ -4259,7 +4328,7 @@ msgstr "Aquest usuari està inclós a la llista <0/> que tens bloquejada" #: src/view/com/modals/ModerationDetails.tsx:74 msgid "This user is included in the <0/> list which you have muted." -msgstr "" +msgstr "Aquest usuari està inclòs a la llista <0/> que has silenciat." #: src/view/com/modals/ModerationDetails.tsx:74 #~ msgid "This user is included the <0/> list which you have muted." @@ -4269,11 +4338,11 @@ msgstr "" msgid "This warning is only available for posts with media attached." msgstr "Aquesta advertència només està disponible per publicacions amb contingut adjuntat." -#: src/components/dialogs/MutedWords.tsx:236 +#: src/components/dialogs/MutedWords.tsx:285 msgid "This will delete {0} from your muted words. You can always add it back later." msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:237 +#: src/view/com/util/forms/PostDropdownBtn.tsx:282 msgid "This will hide this post from your feeds." msgstr "Això amagarà aquesta publicació dels teus canals." @@ -4286,11 +4355,11 @@ msgstr "Preferències dels fils de debat" msgid "Threaded Mode" msgstr "Mode fils de debat" -#: src/Navigation.tsx:255 +#: src/Navigation.tsx:257 msgid "Threads Preferences" msgstr "Preferències dels fils de debat" -#: src/components/dialogs/MutedWords.tsx:95 +#: src/components/dialogs/MutedWords.tsx:113 msgid "Toggle between muted word options." msgstr "" @@ -4304,7 +4373,8 @@ msgstr "Transformacions" #: src/view/com/post-thread/PostThreadItem.tsx:685 #: src/view/com/post-thread/PostThreadItem.tsx:687 -#: src/view/com/util/forms/PostDropdownBtn.tsx:156 +#: src/view/com/util/forms/PostDropdownBtn.tsx:215 +#: src/view/com/util/forms/PostDropdownBtn.tsx:217 msgid "Translate" msgstr "Tradueix" @@ -4369,16 +4439,15 @@ msgid "Unfortunately, you do not meet the requirements to create an account." msgstr "No compleixes les condicions per crear un compte." #: src/view/com/util/post-ctrls/PostCtrls.tsx:182 -#: src/view/com/util/post-ctrls/PostCtrls.tsx:216 msgid "Unlike" msgstr "Desfés el m'agrada" -#: src/components/TagMenu/index.tsx:253 +#: src/components/TagMenu/index.tsx:249 #: src/view/screens/ProfileList.tsx:597 msgid "Unmute" msgstr "Deixa de silenciar" -#: src/components/TagMenu/index.web.tsx:90 +#: src/components/TagMenu/index.web.tsx:104 msgid "Unmute {truncatedTag}" msgstr "" @@ -4386,11 +4455,16 @@ msgstr "" msgid "Unmute Account" msgstr "Deixa de silenciar el compte" -#: src/components/TagMenu/index.tsx:210 -msgid "Unmute all {tag} posts" +#: src/components/TagMenu/index.tsx:208 +msgid "Unmute all {displayTag} posts" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:202 +#: src/components/TagMenu/index.tsx:210 +#~ msgid "Unmute all {tag} posts" +#~ msgstr "" + +#: src/view/com/util/forms/PostDropdownBtn.tsx:251 +#: src/view/com/util/forms/PostDropdownBtn.tsx:256 msgid "Unmute thread" msgstr "Deixa de silenciar el fil de debat" @@ -4474,13 +4548,13 @@ msgstr "Identificador d'usuari" msgid "User list by {0}" msgstr "Llista d'usuaris per {0}" -#: src/view/screens/ProfileList.tsx:762 +#: src/view/screens/ProfileList.tsx:763 msgid "User list by <0/>" msgstr "Llista d'usuaris feta per <0/>" #: src/view/com/lists/ListCard.tsx:83 #: src/view/com/modals/UserAddRemoveLists.tsx:196 -#: src/view/screens/ProfileList.tsx:760 +#: src/view/screens/ProfileList.tsx:761 msgid "User list by you" msgstr "Llista d'usaris feta per tu" @@ -4501,7 +4575,7 @@ msgstr "Llistes d'usuaris" msgid "Username or email address" msgstr "Nom d'usuari o correu" -#: src/view/screens/ProfileList.tsx:796 +#: src/view/screens/ProfileList.tsx:797 msgid "Users" msgstr "Usuaris" @@ -4540,7 +4614,7 @@ msgstr "Verifica el teu correu" #: src/screens/Onboarding/index.tsx:42 msgid "Video Games" -msgstr "" +msgstr "Videojocs" #: src/view/com/profile/ProfileHeader.tsx:662 msgid "View {0}'s avatar" @@ -4573,35 +4647,39 @@ msgstr "Adverteix" #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:134 msgid "We also think you'll like \"For You\" by Skygaze:" +msgstr "També creiem que t'agradarà el canal \"For You\" d'Skygaze:" + +#: src/screens/Hashtag.tsx:132 +msgid "We couldn't find any results for that hashtag." msgstr "" #: src/screens/Deactivated.tsx:133 msgid "We estimate {estimatedTime} until your account is ready." -msgstr "" +msgstr "Calculem {estimatedTime} fins que el teu compte estigui llest." #: src/screens/Onboarding/StepFinished.tsx:93 msgid "We hope you have a wonderful time. Remember, Bluesky is:" -msgstr "" +msgstr "Esperem que t'ho passis pipa. Recorda que Bluesky és:" #: src/view/com/posts/DiscoverFallbackHeader.tsx:29 msgid "We ran out of posts from your follows. Here's the latest from <0/>." msgstr "Ja no hi ha més publicacions dels usuaris que segueixes. Aquà n'hi ha altres de <0/>." -#: src/components/dialogs/MutedWords.tsx:161 +#: src/components/dialogs/MutedWords.tsx:204 msgid "We recommend avoiding common words that appear in many posts, since it can result in no posts being shown." msgstr "" #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:124 msgid "We recommend our \"Discover\" feed:" -msgstr "" +msgstr "Et reomanem el nostre canal \"Discover\":" #: src/screens/Onboarding/StepInterests/index.tsx:133 msgid "We weren't able to connect. Please try again to continue setting up your account. If it continues to fail, you can skip this flow." -msgstr "" +msgstr "No ens hem pogut connectar. Torna-ho a provar per continuar configurant el teu compte. Si continua fallant, pots ometre aquest flux." #: src/screens/Deactivated.tsx:137 msgid "We will let you know when your account is ready." -msgstr "" +msgstr "T'informarem quan el teu compte estigui llest." #: src/view/com/modals/AppealLabel.tsx:48 msgid "We'll look into your appeal promptly." @@ -4609,7 +4687,7 @@ msgstr "Analitzarem la teva apel·lació rà pidament." #: src/screens/Onboarding/StepInterests/index.tsx:138 msgid "We'll use this to help customize your experience." -msgstr "" +msgstr "Ho farem servir per personalitzar la teva experiència." #: src/view/com/auth/create/CreateAccount.tsx:134 msgid "We're so excited to have you join us!" @@ -4619,7 +4697,7 @@ msgstr "Ens fa molta il·lusió que t'uneixis a nosaltres!" msgid "We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @{handleOrDid}." msgstr "Ho sentim, però no hem pogut resoldre aquesta llista. Si això continua, posa't en contacte amb el creador de la llista, @{handleOrDid}." -#: src/components/dialogs/MutedWords.tsx:182 +#: src/components/dialogs/MutedWords.tsx:230 msgid "We're sorry, but we weren't able to load your muted words at this time. Please try again." msgstr "" @@ -4627,6 +4705,7 @@ msgstr "" msgid "We're sorry, but your search could not be completed. Please try again in a few minutes." msgstr "Ens sap greu, però la teva cerca no s'ha pogut fer. Prova-ho d'aquà una estona." +#: src/components/Lists.tsx:211 #: src/view/screens/NotFound.tsx:48 msgid "We're sorry! We can't find the page you were looking for." msgstr "Ens sap greu! No podem trobar la pà gina que està s cercant." @@ -4637,7 +4716,7 @@ msgstr "Benvingut a <0>Bluesky</0>" #: src/screens/Onboarding/StepInterests/index.tsx:130 msgid "What are your interests?" -msgstr "" +msgstr "Quins són els teus interesos?" #: src/view/com/modals/report/Modal.tsx:169 msgid "What is the issue with this {collectionName}?" @@ -4679,7 +4758,7 @@ msgstr "Escriu la teva resposta" #: src/screens/Onboarding/index.tsx:28 msgid "Writers" -msgstr "" +msgstr "Escriptors" #: src/view/com/auth/create/Step2.tsx:263 #~ msgid "XXXXXX" @@ -4697,7 +4776,7 @@ msgstr "SÃ" #: src/screens/Deactivated.tsx:130 msgid "You are in line." -msgstr "" +msgstr "Està s a la cua." #: src/view/com/posts/FollowingEmptyState.tsx:67 #: src/view/com/posts/FollowingEndOfFeed.tsx:68 @@ -4710,7 +4789,7 @@ msgstr "També pots descobrir nous canals personalitzats per seguir." #: src/screens/Onboarding/StepFollowingFeed.tsx:142 msgid "You can change these settings later." -msgstr "" +msgstr "Pots canviar aquests parà metres més endavant." #: src/view/com/auth/login/Login.tsx:158 #: src/view/com/auth/login/PasswordUpdatedForm.tsx:31 @@ -4746,7 +4825,7 @@ msgstr "Has bloquejat aquest usuari. No pots veure el seu contingut." #: src/view/com/modals/ChangePassword.tsx:87 #: src/view/com/modals/ChangePassword.tsx:121 msgid "You have entered an invalid code. It should look like XXXXX-XXXXX." -msgstr "" +msgstr "Has entrat un codi invà lid. Hauria de ser tipus XXXXX-XXXXX." #: src/view/com/modals/ModerationDetails.tsx:87 msgid "You have muted this user." @@ -4773,7 +4852,7 @@ msgstr "Encara no has creat cap contrasenya d'aplicació. Pots fer-ho amb el bot msgid "You have not muted any accounts yet. To mute an account, go to their profile and selected \"Mute account\" from the menu on their account." msgstr "Encara no has silenciat cap compte. Per fer-ho, vés al seu perfil i selecciona \"Silencia compte\" en el menú del seu compte." -#: src/components/dialogs/MutedWords.tsx:202 +#: src/components/dialogs/MutedWords.tsx:250 msgid "You haven't muted any words or tags yet" msgstr "" @@ -4783,13 +4862,13 @@ msgstr "Has de tenir 18 anys o més per habilitar el contingut per a adults." #: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:103 msgid "You must be 18 years or older to enable adult content" -msgstr "" +msgstr "Has de tenir 18 anys o més per habilitar el contingut per a adults" -#: src/view/com/util/forms/PostDropdownBtn.tsx:129 +#: src/view/com/util/forms/PostDropdownBtn.tsx:147 msgid "You will no longer receive notifications for this thread" msgstr "Ja no rebrà s més notificacions d'aquest debat" -#: src/view/com/util/forms/PostDropdownBtn.tsx:132 +#: src/view/com/util/forms/PostDropdownBtn.tsx:150 msgid "You will now receive notifications for this thread" msgstr "Ara rebrà s notificacions d'aquest debat" @@ -4799,23 +4878,23 @@ msgstr "Rebrà s un correu amb un \"codi de restabliment\". Introdueix aquà el c #: src/screens/Onboarding/StepModeration/index.tsx:72 msgid "You're in control" -msgstr "" +msgstr "Tu tens el control" #: src/screens/Deactivated.tsx:87 #: src/screens/Deactivated.tsx:88 #: src/screens/Deactivated.tsx:103 msgid "You're in line" -msgstr "" +msgstr "Està s a la cua" #: src/screens/Onboarding/StepFinished.tsx:90 msgid "You're ready to go!" -msgstr "" +msgstr "Ja està tot llest!" #: src/view/com/posts/FollowingEndOfFeed.tsx:48 msgid "You've reached the end of your feed! Find some more accounts to follow." msgstr "Has arribat al final del vostre cabal! Cerca alguns comptes més per seguir." -#: src/view/com/auth/create/Step1.tsx:74 +#: src/view/com/auth/create/Step1.tsx:67 msgid "Your account" msgstr "El teu compte" @@ -4825,9 +4904,9 @@ msgstr "El teu compte s'ha eliminat" #: src/view/screens/Settings/ExportCarDialog.tsx:47 msgid "Your account repository, containing all public data records, can be downloaded as a \"CAR\" file. This file does not include media embeds, such as images, or your private data, which must be fetched separately." -msgstr "" +msgstr "El repositori del teu compte, que conté tots els registres de dades públiques, es pot baixar com a fitxer \"CAR\". Aquest fitxer no inclou incrustacions multimèdia, com ara imatges, ni les teves dades privades, que s'han d'obtenir per separat." -#: src/view/com/auth/create/Step1.tsx:238 +#: src/view/com/auth/create/Step1.tsx:215 msgid "Your birth date" msgstr "La teva data de naixement" @@ -4837,7 +4916,7 @@ msgstr "La teva elecció es desarà , però es pot canviar més endavant a la con #: src/screens/Onboarding/StepFollowingFeed.tsx:61 msgid "Your default feed is \"Following\"" -msgstr "" +msgstr "El teu canal per defecte és \"Seguint\"" #: src/view/com/auth/create/state.ts:110 #: src/view/com/auth/login/ForgotPasswordForm.tsx:70 @@ -4846,8 +4925,8 @@ msgid "Your email appears to be invalid." msgstr "El teu correu no sembla và lid." #: src/view/com/modals/Waitlist.tsx:109 -msgid "Your email has been saved! We'll be in touch soon." -msgstr "Hem desat el teu correu! Aviat ens posarem en contacte amb tu." +#~ msgid "Your email has been saved! We'll be in touch soon." +#~ msgstr "Hem desat el teu correu! Aviat ens posarem en contacte amb tu." #: src/view/com/modals/ChangeEmail.tsx:125 msgid "Your email has been updated but not verified. As a next step, please verify your new email." @@ -4879,13 +4958,13 @@ msgstr "El teu identificador complet serà <0>@{0}</0>" #~ msgid "Your invite codes are hidden when logged in using an App Password" #~ msgstr "Els teus codis d'invitació no es mostren quan has iniciat sessió amb una contrasenya d'aplicació" -#: src/components/dialogs/MutedWords.tsx:173 +#: src/components/dialogs/MutedWords.tsx:221 msgid "Your muted words" msgstr "" #: src/view/com/modals/ChangePassword.tsx:155 msgid "Your password has been changed successfully!" -msgstr "" +msgstr "S'ha canviat la teva contrasenya!" #: src/view/com/composer/Composer.tsx:274 msgid "Your post has been published" diff --git a/src/locale/locales/de/messages.po b/src/locale/locales/de/messages.po index 1c4188033..503d656ee 100644 --- a/src/locale/locales/de/messages.po +++ b/src/locale/locales/de/messages.po @@ -8,40 +8,22 @@ msgstr "" "Language: de\n" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: \n" +"PO-Revision-Date: 2024-03-12 13:00+0000\n" "Last-Translator: \n" -"Language-Team: \n" +"Language-Team: Translators in PR 2319, PythooonUser, cdfzo\n" "Plural-Forms: \n" #: src/view/com/modals/VerifyEmail.tsx:142 msgid "(no email)" -msgstr "" - -#: src/view/shell/desktop/RightNav.tsx:168 -#~ msgid "{0, plural, one {# invite code available} other {# invite codes available}}" -#~ msgstr "" +msgstr "(keine E-Mail)" #: src/view/com/profile/ProfileHeader.tsx:593 msgid "{following} following" -msgstr "" - -#: src/view/shell/desktop/RightNav.tsx:151 -#~ msgid "{invitesAvailable, plural, one {Invite codes: # available} other {Invite codes: # available}}" -#~ msgstr "" - -#: src/view/screens/Settings.tsx:435 -#: src/view/shell/Drawer.tsx:664 -#~ msgid "{invitesAvailable} invite code available" -#~ msgstr "{invitesAvailable} Einladungscode verfügbar" - -#: src/view/screens/Settings.tsx:437 -#: src/view/shell/Drawer.tsx:666 -#~ msgid "{invitesAvailable} invite codes available" -#~ msgstr "{invitesAvailable} Einladungscodes verfügbar" +msgstr "{following} folge ich" #: src/view/shell/Drawer.tsx:440 msgid "{numUnreadNotifications} unread" -msgstr "" +msgstr "{numUnreadNotifications} ungelesen" #: src/view/com/threadgate/WhoCanReply.tsx:158 msgid "<0/> members" @@ -49,7 +31,7 @@ msgstr "<0/> Mitglieder" #: src/view/com/profile/ProfileHeader.tsx:595 msgid "<0>{following} </0><1>following</1>" -msgstr "" +msgstr "<0>{following} </0><1>folge ich</1>" #: src/view/com/auth/onboarding/RecommendedFeeds.tsx:30 msgid "<0>Choose your</0><1>Recommended</1><2>Feeds</2>" @@ -61,11 +43,11 @@ msgstr "<0>Folge einigen</0><1>empfohlenen</1><2>Nutzern</2>" #: src/view/com/auth/onboarding/WelcomeDesktop.tsx:21 msgid "<0>Welcome to</0><1>Bluesky</1>" -msgstr "" +msgstr "<0>Willkommen bei</0><1>Bluesky</1>" #: src/view/com/profile/ProfileHeader.tsx:558 msgid "âš Invalid Handle" -msgstr "" +msgstr "âš Ungültiger Handle" #: src/view/com/util/moderation/LabelInfo.tsx:45 msgid "A content warning has been applied to this {0}." @@ -75,14 +57,14 @@ msgstr "Diese Seite wurde mit einer Inhaltswarnung versehen {0}." msgid "A new version of the app is available. Please update to continue using the app." msgstr "Eine neue Version der App ist verfügbar. Bitte aktualisiere die App, um sie weiter nutzen zu können." -#: src/view/com/util/ViewHeader.tsx:83 +#: src/view/com/util/ViewHeader.tsx:89 #: src/view/screens/Search/Search.tsx:647 msgid "Access navigation links and settings" -msgstr "" +msgstr "Zugriff auf Navigationslinks und Einstellungen" -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:51 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:52 msgid "Access profile and other navigation links" -msgstr "" +msgstr "Zugang zum Profil und anderen Navigationslinks" #: src/view/com/modals/EditImage.tsx:299 #: src/view/screens/Settings/index.tsx:451 @@ -97,19 +79,19 @@ msgstr "Konto" #: src/view/com/profile/ProfileHeader.tsx:246 msgid "Account blocked" -msgstr "" +msgstr "Konto blockiert" #: src/view/com/profile/ProfileHeader.tsx:213 msgid "Account muted" -msgstr "" +msgstr "Konto stummgeschaltet" #: src/view/com/modals/ModerationDetails.tsx:86 msgid "Account Muted" -msgstr "" +msgstr "Konto Stummgeschaltet" #: src/view/com/modals/ModerationDetails.tsx:72 msgid "Account Muted by List" -msgstr "" +msgstr "Konto stummgeschaltet nach Liste" #: src/view/com/util/AccountDropdownBtn.tsx:41 msgid "Account options" @@ -117,21 +99,21 @@ msgstr "Kontoeinstellungen" #: src/view/com/util/AccountDropdownBtn.tsx:25 msgid "Account removed from quick access" -msgstr "" +msgstr "Konto aus dem Schnellzugriff entfernt" #: src/view/com/profile/ProfileHeader.tsx:268 msgid "Account unblocked" -msgstr "" +msgstr "Konto entblockiert" #: src/view/com/profile/ProfileHeader.tsx:226 msgid "Account unmuted" -msgstr "" +msgstr "Konto Stummschaltung aufgehoben" -#: src/components/dialogs/MutedWords.tsx:147 +#: src/components/dialogs/MutedWords.tsx:165 #: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:150 #: src/view/com/modals/ListAddRemoveUsers.tsx:264 #: src/view/com/modals/UserAddRemoveLists.tsx:219 -#: src/view/screens/ProfileList.tsx:812 +#: src/view/screens/ProfileList.tsx:813 msgid "Add" msgstr "Hinzufügen" @@ -139,7 +121,7 @@ msgstr "Hinzufügen" msgid "Add a content warning" msgstr "Eine Inhaltswarnung hinzufügen" -#: src/view/screens/ProfileList.tsx:802 +#: src/view/screens/ProfileList.tsx:803 msgid "Add a user to this list" msgstr "Einen Nutzer zu dieser Liste hinzufügen" @@ -158,7 +140,7 @@ msgstr "Alt-Text hinzufügen" #: src/view/screens/AppPasswords.tsx:143 #: src/view/screens/AppPasswords.tsx:156 msgid "Add App Password" -msgstr "" +msgstr "App-Passwort hinzufügen" #: src/view/com/modals/report/InputIssueDetails.tsx:41 #: src/view/com/modals/report/Modal.tsx:191 @@ -177,13 +159,13 @@ msgstr "Link-Karte hinzufügen" msgid "Add link card:" msgstr "Link-Karte hinzufügen:" -#: src/components/dialogs/MutedWords.tsx:140 +#: src/components/dialogs/MutedWords.tsx:158 msgid "Add mute word for configured settings" -msgstr "" +msgstr "Stummgeschaltetes Wort für konfigurierte Einstellungen hinzufügen" -#: src/components/dialogs/MutedWords.tsx:74 +#: src/components/dialogs/MutedWords.tsx:87 msgid "Add muted words and tags" -msgstr "" +msgstr "Füge stummgeschaltete Wörter und Tags hinzu" #: src/view/com/modals/ChangeHandle.tsx:417 msgid "Add the following DNS record to your domain:" @@ -200,7 +182,7 @@ msgstr "Zu meinen Feeds hinzufügen" #: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:139 msgid "Added" -msgstr "" +msgstr "Hinzugefügt" #: src/view/com/modals/ListAddRemoveUsers.tsx:191 #: src/view/com/modals/UserAddRemoveLists.tsx:144 @@ -209,7 +191,7 @@ msgstr "Zur Liste hinzugefügt" #: src/view/com/feeds/FeedSourceCard.tsx:127 msgid "Added to my feeds" -msgstr "" +msgstr "Zu meinen Feeds hinzugefügt" #: src/view/screens/PreferencesFollowingFeed.tsx:173 msgid "Adjust the number of likes a reply must have to be shown in your feed." @@ -221,11 +203,7 @@ msgstr "Inhalt für Erwachsene" #: src/view/com/modals/ContentFilteringSettings.tsx:141 msgid "Adult content can only be enabled via the Web at <0/>." -msgstr "" - -#: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:78 -#~ msgid "Adult content can only be enabled via the Web at <0>bsky.app</0>." -#~ msgstr "" +msgstr "Inhalte für Erwachsene können nur über das Web unter <0/> aktiviert werden." #: src/view/screens/Settings/index.tsx:664 msgid "Advanced" @@ -233,16 +211,16 @@ msgstr "Erweitert" #: src/view/screens/Feeds.tsx:666 msgid "All the feeds you've saved, right in one place." -msgstr "" +msgstr "All deine gespeicherten Feeds an einem Ort." #: src/view/com/auth/login/ForgotPasswordForm.tsx:221 #: src/view/com/modals/ChangePassword.tsx:168 msgid "Already have a code?" -msgstr "" +msgstr "Hast du bereits einen Code?" #: src/view/com/auth/login/ChooseAccountForm.tsx:98 msgid "Already signed in as @{0}" -msgstr "" +msgstr "Bereits angemeldet als @{0}" #: src/view/com/composer/photos/Gallery.tsx:130 msgid "ALT" @@ -258,7 +236,7 @@ msgstr "Alt-Text beschreibt Bilder für blinde und sehbehinderte Nutzer und hilf #: src/view/com/modals/VerifyEmail.tsx:124 msgid "An email has been sent to {0}. It includes a confirmation code which you can enter below." -msgstr "Eine E-Mail wurde an {0} gesendet . Sie enthält einen Bestätigungscode, den du unten eingeben kannst." +msgstr "Eine E-Mail wurde an {0} gesendet. Sie enthält einen Bestätigungscode, den du unten eingeben kannst." #: src/view/com/modals/ChangeEmail.tsx:119 msgid "An email has been sent to your previous address, {0}. It includes a confirmation code which you can enter below." @@ -267,16 +245,16 @@ msgstr "Eine E-Mail wurde an deine vorherige Adresse {0} gesendet. Sie enthält #: src/view/com/profile/FollowButton.tsx:30 #: src/view/com/profile/FollowButton.tsx:40 msgid "An issue occurred, please try again." -msgstr "" +msgstr "Es ist ein Problem aufgetreten, bitte versuche es erneut." -#: src/view/com/notifications/FeedItem.tsx:236 +#: src/view/com/notifications/FeedItem.tsx:237 #: src/view/com/threadgate/WhoCanReply.tsx:178 msgid "and" msgstr "und" #: src/screens/Onboarding/index.tsx:32 msgid "Animals" -msgstr "" +msgstr "Tiere" #: src/view/screens/LanguageSettings.tsx:95 msgid "App Language" @@ -284,37 +262,34 @@ msgstr "App-Sprache" #: src/view/screens/AppPasswords.tsx:228 msgid "App password deleted" -msgstr "" +msgstr "App-Passwort gelöscht" #: src/view/com/modals/AddAppPasswords.tsx:134 msgid "App Password names can only contain letters, numbers, spaces, dashes, and underscores." -msgstr "" +msgstr "App-Passwortnamen dürfen nur Buchstaben, Zahlen, Leerzeichen, Bindestriche und Unterstriche enthalten." #: src/view/com/modals/AddAppPasswords.tsx:99 msgid "App Password names must be at least 4 characters long." -msgstr "" +msgstr "App-Passwortnamen müssen mindestens 4 Zeichen lang sein." #: src/view/screens/Settings/index.tsx:675 msgid "App password settings" -msgstr "" +msgstr "App-Passwort-Einstellungen" -#: src/view/screens/Settings.tsx:650 -#~ msgid "App passwords" -#~ msgstr "App-Passwörter" - -#: src/Navigation.tsx:237 +#: src/Navigation.tsx:239 #: src/view/screens/AppPasswords.tsx:187 #: src/view/screens/Settings/index.tsx:684 msgid "App Passwords" msgstr "App-Passwörter" -#: src/view/com/util/forms/PostDropdownBtn.tsx:295 +#: src/view/com/util/forms/PostDropdownBtn.tsx:337 +#: src/view/com/util/forms/PostDropdownBtn.tsx:346 msgid "Appeal content warning" -msgstr "" +msgstr "Inhaltswarnungseinspruch" #: src/view/com/modals/AppealLabel.tsx:65 msgid "Appeal Content Warning" -msgstr "" +msgstr "Inhaltswarnungseinspruch" #: src/view/com/util/moderation/LabelInfo.tsx:52 msgid "Appeal this decision" @@ -336,22 +311,22 @@ msgstr "Bist du sicher, dass du das App-Passwort \"{name}\" löschen möchtest?" msgid "Are you sure you'd like to discard this draft?" msgstr "Bist du sicher, dass du diesen Entwurf verwerfen möchtest?" -#: src/components/dialogs/MutedWords.tsx:233 +#: src/components/dialogs/MutedWords.tsx:282 #: src/view/screens/ProfileList.tsx:365 msgid "Are you sure?" msgstr "Bist du sicher?" -#: src/view/com/util/forms/PostDropdownBtn.tsx:278 +#: src/view/com/util/forms/PostDropdownBtn.tsx:322 msgid "Are you sure? This cannot be undone." msgstr "Bist du sicher? Dies kann nicht rückgängig gemacht werden." #: src/view/com/composer/select-language/SuggestedLanguage.tsx:60 msgid "Are you writing in <0>{0}</0>?" -msgstr "" +msgstr "Schreibst du auf <0>{0}</0>?" #: src/screens/Onboarding/index.tsx:26 msgid "Art" -msgstr "" +msgstr "Kunst" #: src/view/com/modals/SelfLabel.tsx:123 msgid "Artistic or non-erotic nudity." @@ -367,24 +342,24 @@ msgstr "Künstlerische oder nicht-erotische Nacktheit." #: src/view/com/post-thread/PostThread.tsx:522 #: src/view/com/post-thread/PostThread.tsx:530 #: src/view/com/profile/ProfileHeader.tsx:649 -#: src/view/com/util/ViewHeader.tsx:81 +#: src/view/com/util/ViewHeader.tsx:87 msgid "Back" msgstr "Zurück" #: src/view/com/post-thread/PostThread.tsx:480 msgctxt "action" msgid "Back" -msgstr "" +msgstr "Zurück" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:136 msgid "Based on your interest in {interestsText}" -msgstr "" +msgstr "Ausgehend von deinem Interesse an {interestsText}" #: src/view/screens/Settings/index.tsx:523 msgid "Basics" msgstr "Grundlagen" -#: src/view/com/auth/create/Step1.tsx:250 +#: src/view/com/auth/create/Step1.tsx:227 #: src/view/com/modals/BirthDateSettings.tsx:73 msgid "Birthday" msgstr "Geburtstag" @@ -396,11 +371,11 @@ msgstr "Geburtstag:" #: src/view/com/profile/ProfileHeader.tsx:239 #: src/view/com/profile/ProfileHeader.tsx:346 msgid "Block Account" -msgstr "" +msgstr "Konto blockieren" #: src/view/screens/ProfileList.tsx:556 msgid "Block accounts" -msgstr "" +msgstr "Konten blockieren" #: src/view/screens/ProfileList.tsx:506 msgid "Block list" @@ -412,18 +387,18 @@ msgstr "Diese Konten blockieren?" #: src/view/screens/ProfileList.tsx:320 msgid "Block this List" -msgstr "" +msgstr "Diese Liste blockieren" #: src/view/com/lists/ListCard.tsx:110 #: src/view/com/util/post-embeds/QuoteEmbed.tsx:61 msgid "Blocked" -msgstr "" +msgstr "Blockiert" #: src/view/screens/Moderation.tsx:142 msgid "Blocked accounts" msgstr "Blockierte Konten" -#: src/Navigation.tsx:130 +#: src/Navigation.tsx:132 #: src/view/screens/ModerationBlockedAccounts.tsx:107 msgid "Blocked Accounts" msgstr "Blockierte Konten" @@ -457,7 +432,7 @@ msgstr "Bluesky" #: src/view/com/auth/server-input/index.tsx:150 msgid "Bluesky is an open network where you can choose your hosting provider. Custom hosting is now available in beta for developers." -msgstr "" +msgstr "Bluesky ist ein offenes Netzwerk, in dem du deinen Hosting-Anbieter wählen kannst. Benutzerdefiniertes Hosting ist jetzt in der Beta-Phase für Entwickler verfügbar." #: src/view/com/auth/onboarding/WelcomeDesktop.tsx:80 #: src/view/com/auth/onboarding/WelcomeMobile.tsx:80 @@ -474,21 +449,13 @@ msgstr "Bluesky ist offen." msgid "Bluesky is public." msgstr "Bluesky ist öffentlich." -#: src/view/com/modals/Waitlist.tsx:70 -msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon." -msgstr "Bluesky nutzt Einladungen, um eine gesündere Community aufzubauen. Wenn du niemanden kennst, der eine Einladung hat, kannst du dich auf die Warteliste setzen lassen und wir schicken dir bald eine zu." - #: src/view/screens/Moderation.tsx:245 msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private." msgstr "Bluesky zeigt dein Profil und deine Beiträge nicht für abgemeldete Nutzer an. Andere Apps kommen dieser Aufforderung möglicherweise nicht nach." -#: src/view/com/modals/ServerInput.tsx:78 -#~ msgid "Bluesky.Social" -#~ msgstr "Bluesky.Social" - #: src/screens/Onboarding/index.tsx:33 msgid "Books" -msgstr "" +msgstr "Bücher" #: src/view/screens/Settings/index.tsx:859 msgid "Build version {0} {1}" @@ -499,25 +466,21 @@ msgstr "Build-Version {0} {1}" msgid "Business" msgstr "Business" -#: src/view/com/modals/ServerInput.tsx:115 -#~ msgid "Button disabled. Input custom domain to proceed." -#~ msgstr "" - #: src/view/com/profile/ProfileSubpageHeader.tsx:157 msgid "by —" -msgstr "" +msgstr "von —" #: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:100 msgid "by {0}" -msgstr "" +msgstr "von {0}" #: src/view/com/profile/ProfileSubpageHeader.tsx:161 msgid "by <0/>" -msgstr "" +msgstr "von <0/>" #: src/view/com/profile/ProfileSubpageHeader.tsx:159 msgid "by you" -msgstr "" +msgstr "von dir" #: src/view/com/composer/photos/OpenCameraBtn.tsx:60 #: src/view/com/util/UserAvatar.tsx:224 @@ -529,7 +492,7 @@ msgstr "Kamera" msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must be at least 4 characters long, but no more than 32 characters long." msgstr "Darf nur Buchstaben, Zahlen, Leerzeichen, Bindestriche und Unterstriche enthalten. Muss mindestens 4 Zeichen lang sein, darf aber nicht länger als 32 Zeichen sein." -#: src/components/Prompt.tsx:91 +#: src/components/Prompt.tsx:101 #: src/view/com/composer/Composer.tsx:307 #: src/view/com/composer/Composer.tsx:312 #: src/view/com/modals/ChangeEmail.tsx:218 @@ -544,7 +507,6 @@ msgstr "Darf nur Buchstaben, Zahlen, Leerzeichen, Bindestriche und Unterstriche #: src/view/com/modals/Repost.tsx:87 #: src/view/com/modals/VerifyEmail.tsx:247 #: src/view/com/modals/VerifyEmail.tsx:253 -#: src/view/com/modals/Waitlist.tsx:142 #: src/view/screens/Search/Search.tsx:716 #: src/view/shell/desktop/Search.tsx:238 msgid "Cancel" @@ -557,7 +519,7 @@ msgstr "Abbrechen" #: src/view/com/modals/DeleteAccount.tsx:234 msgctxt "action" msgid "Cancel" -msgstr "" +msgstr "Abbrechen" #: src/view/com/modals/DeleteAccount.tsx:152 #: src/view/com/modals/DeleteAccount.tsx:230 @@ -566,29 +528,25 @@ msgstr "Konto-Löschung abbrechen" #: src/view/com/modals/ChangeHandle.tsx:149 msgid "Cancel change handle" -msgstr "" +msgstr "Handle ändern abbrechen" #: src/view/com/modals/crop-image/CropImage.web.tsx:134 msgid "Cancel image crop" -msgstr "" +msgstr "Bildbeschneidung abbrechen" #: src/view/com/modals/EditProfile.tsx:244 msgid "Cancel profile editing" -msgstr "" +msgstr "Profilbearbeitung abbrechen" #: src/view/com/modals/Repost.tsx:78 msgid "Cancel quote post" -msgstr "" +msgstr "Beitrag zitieren abbrechen" #: src/view/com/modals/ListAddRemoveUsers.tsx:87 #: src/view/shell/desktop/Search.tsx:234 msgid "Cancel search" msgstr "Suche abbrechen" -#: src/view/com/modals/Waitlist.tsx:136 -msgid "Cancel waitlist signup" -msgstr "Anmeldung zur Warteliste abbrechen" - #: src/view/screens/Settings/index.tsx:334 msgctxt "action" msgid "Change" @@ -609,19 +567,19 @@ msgstr "Meine E-Mail ändern" #: src/view/screens/Settings/index.tsx:732 msgid "Change password" -msgstr "" +msgstr "Passwort ändern" #: src/view/screens/Settings/index.tsx:741 msgid "Change Password" -msgstr "" +msgstr "Passwort Ändern" #: src/view/com/composer/select-language/SuggestedLanguage.tsx:73 msgid "Change post language to {0}" -msgstr "" +msgstr "Beitragssprache in {0} ändern" #: src/view/screens/Settings/index.tsx:733 msgid "Change your Bluesky password" -msgstr "" +msgstr "Ändere dein Bluesky-Passwort" #: src/view/com/modals/ChangeEmail.tsx:109 msgid "Change Your Email" @@ -630,7 +588,7 @@ msgstr "Deine E-Mail ändern" #: src/screens/Deactivated.tsx:72 #: src/screens/Deactivated.tsx:76 msgid "Check my status" -msgstr "" +msgstr "Meinen Status prüfen" #: src/view/com/auth/onboarding/RecommendedFeeds.tsx:121 msgid "Check out some recommended feeds. Tap + to add them to your list of pinned feeds." @@ -646,11 +604,11 @@ msgstr "Überprüfe deinen Posteingang auf eine E-Mail mit dem Bestätigungscode #: src/view/com/modals/Threadgate.tsx:72 msgid "Choose \"Everybody\" or \"Nobody\"" -msgstr "" +msgstr "Wähle \"Alle\" oder \"Niemand\"" #: src/view/screens/Settings/index.tsx:697 msgid "Choose a new Bluesky username or create" -msgstr "" +msgstr "Wähle oder erstelle einen neuen Bluesky-Benutzernamen" #: src/view/com/auth/server-input/index.tsx:79 msgid "Choose Service" @@ -658,22 +616,18 @@ msgstr "Service wählen" #: src/screens/Onboarding/StepFinished.tsx:135 msgid "Choose the algorithms that power your custom feeds." -msgstr "" +msgstr "Wähle die Algorithmen aus, welche deine benutzerdefinierten Feeds generieren." #: src/view/com/auth/onboarding/WelcomeDesktop.tsx:83 #: src/view/com/auth/onboarding/WelcomeMobile.tsx:83 msgid "Choose the algorithms that power your experience with custom feeds." -msgstr "" - -#: src/screens/Onboarding/StepAlgoFeeds/index.tsx:103 -#~ msgid "Choose your algorithmic feeds" -#~ msgstr "" +msgstr "Wähle die Algorithmen aus, welche dein Erlebnis mit benutzerdefinierten Feeds unterstützen." #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:103 msgid "Choose your main feeds" -msgstr "" +msgstr "Wähle deine Haupt-Feeds" -#: src/view/com/auth/create/Step1.tsx:219 +#: src/view/com/auth/create/Step1.tsx:196 msgid "Choose your password" msgstr "Wähle dein Passwort" @@ -702,34 +656,37 @@ msgstr "Suchanfrage löschen" #: src/view/screens/Support.tsx:40 msgid "click here" -msgstr "" +msgstr "hier klicken" -#: src/components/RichText.tsx:189 -#: src/components/TagMenu/index.web.tsx:125 +#: src/components/TagMenu/index.web.tsx:138 msgid "Click here to open tag menu for {tag}" -msgstr "" +msgstr "Klicke hier, um das Tag-Menü für {tag} zu öffnen" + +#: src/components/RichText.tsx:191 +msgid "Click here to open tag menu for #{tag}" +msgstr "Klicke hier, um das Tag-Menü für #{tag} zu öffnen" #: src/screens/Onboarding/index.tsx:35 msgid "Climate" -msgstr "" +msgstr "Klima" #: src/view/com/modals/ChangePassword.tsx:265 #: src/view/com/modals/ChangePassword.tsx:268 msgid "Close" -msgstr "" +msgstr "Schließen" -#: src/components/Dialog/index.web.tsx:80 -#: src/components/Dialog/index.web.tsx:194 +#: src/components/Dialog/index.web.tsx:84 +#: src/components/Dialog/index.web.tsx:198 msgid "Close active dialog" -msgstr "" +msgstr "Aktiven Dialog schließen" #: src/view/com/auth/login/PasswordUpdatedForm.tsx:38 msgid "Close alert" -msgstr "" +msgstr "Meldung schließen" #: src/view/com/util/BottomSheetCustomBackdrop.tsx:33 msgid "Close bottom drawer" -msgstr "" +msgstr "Untere Schublade schließen" #: src/view/com/lightbox/ImageViewing/components/ImageDefaultHeader.tsx:26 msgid "Close image" @@ -737,60 +694,60 @@ msgstr "Bild schließen" #: src/view/com/lightbox/Lightbox.web.tsx:119 msgid "Close image viewer" -msgstr "" +msgstr "Bildbetrachter schließen" #: src/view/shell/index.web.tsx:51 msgid "Close navigation footer" -msgstr "" +msgstr "Fußzeile der Navigation schließen" -#: src/components/TagMenu/index.tsx:266 +#: src/components/TagMenu/index.tsx:262 msgid "Close this dialog" -msgstr "" +msgstr "Diesen Dialog schließen" #: src/view/shell/index.web.tsx:52 msgid "Closes bottom navigation bar" -msgstr "" +msgstr "Schließt die untere Navigationsleiste" #: src/view/com/auth/login/PasswordUpdatedForm.tsx:39 msgid "Closes password update alert" -msgstr "" +msgstr "Schließt die Kennwortaktualisierungsmeldung" #: src/view/com/composer/Composer.tsx:309 msgid "Closes post composer and discards post draft" -msgstr "" +msgstr "Schließt den Beitragsverfasser und verwirft den Beitragsentwurf" #: src/view/com/lightbox/ImageViewing/components/ImageDefaultHeader.tsx:27 msgid "Closes viewer for header image" -msgstr "" +msgstr "Schließt den Betrachter für das Banner" -#: src/view/com/notifications/FeedItem.tsx:317 +#: src/view/com/notifications/FeedItem.tsx:318 msgid "Collapses list of users for a given notification" -msgstr "" +msgstr "Klappt die Liste der Benutzer für eine bestimmte Meldung zusammen" #: src/screens/Onboarding/index.tsx:41 msgid "Comedy" -msgstr "" +msgstr "Komödie" #: src/screens/Onboarding/index.tsx:27 msgid "Comics" -msgstr "" +msgstr "Comics" -#: src/Navigation.tsx:227 +#: src/Navigation.tsx:229 #: src/view/screens/CommunityGuidelines.tsx:32 msgid "Community Guidelines" msgstr "Community-Richtlinien" #: src/screens/Onboarding/StepFinished.tsx:148 msgid "Complete onboarding and start using your account" -msgstr "" +msgstr "Schließe das Onboarding ab und nutze dein Konto" #: src/view/com/auth/create/Step3.tsx:73 msgid "Complete the challenge" -msgstr "" +msgstr "Beende die Herausforderung" #: src/view/com/composer/Composer.tsx:424 msgid "Compose posts up to {MAX_GRAPHEME_LENGTH} characters in length" -msgstr "" +msgstr "Verfasse Beiträge mit einer Länge von bis zu {MAX_GRAPHEME_LENGTH} Zeichen" #: src/view/com/composer/Prompt.tsx:24 msgid "Compose reply" @@ -798,9 +755,9 @@ msgstr "Antwort verfassen" #: src/screens/Onboarding/StepModeration/ModerationOption.tsx:67 msgid "Configure content filtering setting for category: {0}" -msgstr "" +msgstr "Inhaltsfilterungseinstellung der Kategorie {0} konfigurieren" -#: src/components/Prompt.tsx:113 +#: src/components/Prompt.tsx:124 #: src/view/com/modals/AppealLabel.tsx:98 #: src/view/com/modals/SelfLabel.tsx:154 #: src/view/com/modals/VerifyEmail.tsx:231 @@ -814,7 +771,7 @@ msgstr "Bestätigen" #: src/view/com/modals/Confirm.tsx:78 msgctxt "action" msgid "Confirm" -msgstr "" +msgstr "Bestätigen" #: src/view/com/modals/ChangeEmail.tsx:193 #: src/view/com/modals/ChangeEmail.tsx:195 @@ -831,7 +788,7 @@ msgstr "Bestätige das Löschen des Kontos" #: src/view/com/modals/ContentFilteringSettings.tsx:156 msgid "Confirm your age to enable adult content." -msgstr "" +msgstr "Bestätige dein Alter, um Inhalte für Erwachsene zu aktivieren." #: src/view/com/modals/ChangeEmail.tsx:157 #: src/view/com/modals/DeleteAccount.tsx:182 @@ -839,10 +796,6 @@ msgstr "" msgid "Confirmation code" msgstr "Bestätigungscode" -#: src/view/com/modals/Waitlist.tsx:120 -msgid "Confirms signing up {email} to the waitlist" -msgstr "" - #: src/view/com/auth/create/CreateAccount.tsx:193 #: src/view/com/auth/login/LoginForm.tsx:278 msgid "Connecting..." @@ -850,7 +803,7 @@ msgstr "Verbinden..." #: src/view/com/auth/create/CreateAccount.tsx:213 msgid "Contact support" -msgstr "" +msgstr "Support kontaktieren" #: src/view/screens/Moderation.tsx:83 msgid "Content filtering" @@ -863,11 +816,11 @@ msgstr "Inhaltsfilterung" #: src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx:74 #: src/view/screens/LanguageSettings.tsx:278 msgid "Content Languages" -msgstr "" +msgstr "Inhaltssprachen" #: src/view/com/modals/ModerationDetails.tsx:65 msgid "Content Not Available" -msgstr "" +msgstr "Inhalt nicht verfügbar" #: src/view/com/modals/ModerationDetails.tsx:33 #: src/view/com/util/moderation/ScreenHider.tsx:78 @@ -893,19 +846,19 @@ msgstr "Fortfahren" #: src/screens/Onboarding/StepModeration/index.tsx:115 #: src/screens/Onboarding/StepTopicalFeeds.tsx:111 msgid "Continue to next step" -msgstr "" +msgstr "Weiter zum nächsten Schritt" #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:167 msgid "Continue to the next step" -msgstr "" +msgstr "Weiter zum nächsten Schritt" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:191 msgid "Continue to the next step without following any accounts" -msgstr "" +msgstr "Fahre mit dem nächsten Schritt fort, ohne Konten zu folgen" #: src/screens/Onboarding/index.tsx:44 msgid "Cooking" -msgstr "" +msgstr "Kochen" #: src/view/com/modals/AddAppPasswords.tsx:195 #: src/view/com/modals/InviteCodes.tsx:182 @@ -914,17 +867,17 @@ msgstr "Kopiert" #: src/view/screens/Settings/index.tsx:241 msgid "Copied build version to clipboard" -msgstr "" +msgstr "Die Build-Version wurde in die Zwischenablage kopiert" #: src/view/com/modals/AddAppPasswords.tsx:76 #: src/view/com/modals/InviteCodes.tsx:152 -#: src/view/com/util/forms/PostDropdownBtn.tsx:143 +#: src/view/com/util/forms/PostDropdownBtn.tsx:161 msgid "Copied to clipboard" -msgstr "" +msgstr "In die Zwischenablage kopiert" #: src/view/com/modals/AddAppPasswords.tsx:189 msgid "Copies app password" -msgstr "" +msgstr "Kopiert das App-Passwort" #: src/view/com/modals/AddAppPasswords.tsx:188 msgid "Copy" @@ -934,7 +887,8 @@ msgstr "Kopieren" msgid "Copy link to list" msgstr "Link zur Liste kopieren" -#: src/view/com/util/forms/PostDropdownBtn.tsx:184 +#: src/view/com/util/forms/PostDropdownBtn.tsx:231 +#: src/view/com/util/forms/PostDropdownBtn.tsx:237 msgid "Copy link to post" msgstr "Link zum Beitrag kopieren" @@ -942,27 +896,24 @@ msgstr "Link zum Beitrag kopieren" msgid "Copy link to profile" msgstr "Link zum Profil kopieren" -#: src/view/com/util/forms/PostDropdownBtn.tsx:170 +#: src/view/com/util/forms/PostDropdownBtn.tsx:223 +#: src/view/com/util/forms/PostDropdownBtn.tsx:225 msgid "Copy post text" -msgstr "" +msgstr "Beitragstext kopieren" -#: src/Navigation.tsx:232 +#: src/Navigation.tsx:234 #: src/view/screens/CopyrightPolicy.tsx:29 msgid "Copyright Policy" -msgstr "" +msgstr "Urheberrechtsbestimmungen" #: src/view/screens/ProfileFeed.tsx:97 msgid "Could not load feed" msgstr "Feed konnte nicht geladen werden" -#: src/view/screens/ProfileList.tsx:888 +#: src/view/screens/ProfileList.tsx:893 msgid "Could not load list" msgstr "Liste konnte nicht geladen werden" -#: src/view/com/auth/create/Step2.tsx:91 -#~ msgid "Country" -#~ msgstr "" - #: src/view/com/auth/HomeLoggedOutCTA.tsx:62 #: src/view/com/auth/SplashScreen.tsx:71 #: src/view/com/auth/SplashScreen.web.tsx:81 @@ -971,7 +922,7 @@ msgstr "Ein neues Konto erstellen" #: src/view/screens/Settings/index.tsx:384 msgid "Create a new Bluesky account" -msgstr "" +msgstr "Erstelle ein neues Bluesky-Konto" #: src/view/com/auth/create/CreateAccount.tsx:133 msgid "Create Account" @@ -979,7 +930,7 @@ msgstr "Konto erstellen" #: src/view/com/modals/AddAppPasswords.tsx:226 msgid "Create App Password" -msgstr "" +msgstr "App-Passwort erstellen" #: src/view/com/auth/HomeLoggedOutCTA.tsx:54 #: src/view/com/auth/SplashScreen.tsx:68 @@ -992,24 +943,24 @@ msgstr "Erstellt {0}" #: src/view/screens/ProfileFeed.tsx:616 msgid "Created by <0/>" -msgstr "" +msgstr "Erstellt von <0/>" #: src/view/screens/ProfileFeed.tsx:614 msgid "Created by you" -msgstr "" +msgstr "Erstellt von dir" #: src/view/com/composer/Composer.tsx:455 msgid "Creates a card with a thumbnail. The card links to {url}" -msgstr "" +msgstr "Erzeugt eine Karte mit Vorschaubild und verlinkt auf {url}" #: src/screens/Onboarding/index.tsx:29 msgid "Culture" -msgstr "" +msgstr "Kultur" #: src/view/com/auth/server-input/index.tsx:95 #: src/view/com/auth/server-input/index.tsx:96 msgid "Custom" -msgstr "" +msgstr "Benutzerdefiniert" #: src/view/com/modals/ChangeHandle.tsx:389 msgid "Custom domain" @@ -1018,32 +969,28 @@ msgstr "Benutzerdefinierte Domain" #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:106 #: src/view/screens/Feeds.tsx:692 msgid "Custom feeds built by the community bring you new experiences and help you find the content you love." -msgstr "" +msgstr "Benutzerdefinierte Feeds, die von der Community erstellt wurden, bringen dir neue Erfahrungen und helfen dir, die Inhalte zu finden, die du liebst." #: src/view/screens/PreferencesExternalEmbeds.tsx:55 msgid "Customize media from external sites." -msgstr "" - -#: src/view/screens/Settings.tsx:687 -#~ msgid "Danger Zone" -#~ msgstr "" +msgstr "Passe die Einstellungen für Medien von externen Websites an." #: src/view/screens/Settings/index.tsx:485 #: src/view/screens/Settings/index.tsx:511 msgid "Dark" -msgstr "" +msgstr "Dunkel" #: src/view/screens/Debug.tsx:63 msgid "Dark mode" -msgstr "" +msgstr "Dunkelmodus" #: src/view/screens/Settings/index.tsx:498 msgid "Dark Theme" -msgstr "" +msgstr "Dunkles Thema" #: src/view/screens/Debug.tsx:83 msgid "Debug panel" -msgstr "" +msgstr "Debug-Panel" #: src/view/screens/Settings/index.tsx:772 msgid "Delete account" @@ -1067,25 +1014,22 @@ msgstr "Liste löschen" msgid "Delete my account" msgstr "Mein Konto löschen" -#: src/view/screens/Settings.tsx:706 -#~ msgid "Delete my account…" -#~ msgstr "Mein Konto löschen…" - #: src/view/screens/Settings/index.tsx:784 msgid "Delete My Account…" -msgstr "" +msgstr "Mein Konto Löschen…" -#: src/view/com/util/forms/PostDropdownBtn.tsx:273 +#: src/view/com/util/forms/PostDropdownBtn.tsx:317 +#: src/view/com/util/forms/PostDropdownBtn.tsx:326 msgid "Delete post" msgstr "Beitrag löschen" -#: src/view/com/util/forms/PostDropdownBtn.tsx:277 +#: src/view/com/util/forms/PostDropdownBtn.tsx:321 msgid "Delete this post?" msgstr "Diesen Beitrag löschen?" #: src/view/com/util/post-embeds/QuoteEmbed.tsx:70 msgid "Deleted" -msgstr "" +msgstr "Gelöscht" #: src/view/com/post-thread/PostThread.tsx:316 msgid "Deleted post." @@ -1098,17 +1042,13 @@ msgstr "Gelöschter Beitrag." msgid "Description" msgstr "Beschreibung" -#: src/view/screens/Settings.tsx:760 -#~ msgid "Developer Tools" -#~ msgstr "Entwickler-Tools" - #: src/view/com/composer/Composer.tsx:218 msgid "Did you want to say anything?" -msgstr "" +msgstr "Wolltest du etwas sagen?" #: src/view/screens/Settings/index.tsx:504 msgid "Dim" -msgstr "" +msgstr "Dimmen" #: src/view/com/composer/Composer.tsx:151 msgid "Discard" @@ -1125,15 +1065,11 @@ msgstr "Apps daran hindern, abgemeldeten Nutzern mein Konto zu zeigen" #: src/view/com/posts/FollowingEmptyState.tsx:74 #: src/view/com/posts/FollowingEndOfFeed.tsx:75 msgid "Discover new custom feeds" -msgstr "" - -#: src/view/screens/Feeds.tsx:473 -#~ msgid "Discover new feeds" -#~ msgstr "Entdecke neue Feeds" +msgstr "Entdecke neue benutzerdefinierte Feeds" #: src/view/screens/Feeds.tsx:689 msgid "Discover New Feeds" -msgstr "" +msgstr "Entdecke neue Feeds" #: src/view/com/modals/EditProfile.tsx:192 msgid "Display name" @@ -1147,10 +1083,6 @@ msgstr "Anzeigename" msgid "Domain verified!" msgstr "Domain verifiziert!" -#: src/view/com/auth/create/Step1.tsx:170 -msgid "Don't have an invite code?" -msgstr "" - #: src/view/com/auth/onboarding/RecommendedFollows.tsx:86 #: src/view/com/modals/EditImage.tsx:333 #: src/view/com/modals/ListAddRemoveUsers.tsx:144 @@ -1162,7 +1094,7 @@ msgstr "" #: src/view/screens/PreferencesThreads.tsx:162 msgctxt "action" msgid "Done" -msgstr "" +msgstr "Erledigt" #: src/view/com/auth/server-input/index.tsx:165 #: src/view/com/auth/server-input/index.tsx:166 @@ -1186,48 +1118,48 @@ msgstr "Erledigt{extraText}" #: src/view/com/auth/login/ChooseAccountForm.tsx:45 msgid "Double tap to sign in" -msgstr "" +msgstr "Doppeltippen zum Anmelden" #: src/view/screens/Settings/index.tsx:755 msgid "Download Bluesky account data (repository)" -msgstr "" +msgstr "Öffnet ein Modal zum Herunterladen deiner Bluesky-Kontodaten (Kontodepot)" #: src/view/screens/Settings/ExportCarDialog.tsx:59 #: src/view/screens/Settings/ExportCarDialog.tsx:63 msgid "Download CAR file" -msgstr "" +msgstr "CAR-Datei herunterladen" #: src/view/com/composer/text-input/TextInput.web.tsx:249 msgid "Drop to add images" -msgstr "" +msgstr "Ablegen zum Hinzufügen von Bildern" #: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:111 msgid "Due to Apple policies, adult content can only be enabled on the web after completing sign up." -msgstr "" +msgstr "Aufgrund der Apple-Richtlinien können Inhalte für Erwachsene erst nach Abschluss der Registrierung auf der Website aktiviert werden." #: src/view/com/modals/EditProfile.tsx:185 msgid "e.g. Alice Roberts" -msgstr "" +msgstr "z.B. Alice Roberts" #: src/view/com/modals/EditProfile.tsx:203 msgid "e.g. Artist, dog-lover, and avid reader." -msgstr "" +msgstr "z.B. Künstlerin, Hundeliebhaberin und begeisterte Leserin." #: src/view/com/modals/CreateOrEditList.tsx:283 msgid "e.g. Great Posters" -msgstr "" +msgstr "z.B. Große Poster" #: src/view/com/modals/CreateOrEditList.tsx:284 msgid "e.g. Spammers" -msgstr "" +msgstr "z.B. Spammer" #: src/view/com/modals/CreateOrEditList.tsx:312 msgid "e.g. The posters who never miss." -msgstr "" +msgstr "z.B. Die Poster, die immer ins Schwarze treffen." #: src/view/com/modals/CreateOrEditList.tsx:313 msgid "e.g. Users that repeatedly reply with ads." -msgstr "" +msgstr "z.B. Nutzer, die wiederholt mit Werbung antworten." #: src/view/com/modals/InviteCodes.tsx:96 msgid "Each code works once. You'll receive more invite codes periodically." @@ -1236,7 +1168,7 @@ msgstr "Jeder Code funktioniert einmal. Du erhältst regelmäßig neue Einladung #: src/view/com/lists/ListMembers.tsx:149 msgctxt "action" msgid "Edit" -msgstr "" +msgstr "Bearbeiten" #: src/view/com/composer/photos/Gallery.tsx:144 #: src/view/com/modals/EditImage.tsx:207 @@ -1249,9 +1181,9 @@ msgstr "Details der Liste bearbeiten" #: src/view/com/modals/CreateOrEditList.tsx:250 msgid "Edit Moderation List" -msgstr "" +msgstr "Moderationsliste bearbeiten" -#: src/Navigation.tsx:242 +#: src/Navigation.tsx:244 #: src/view/screens/Feeds.tsx:434 #: src/view/screens/SavedFeeds.tsx:84 msgid "Edit My Feeds" @@ -1269,35 +1201,34 @@ msgstr "Profil bearbeiten" msgid "Edit Profile" msgstr "Profil bearbeiten" -#: src/view/com/home/HomeHeaderLayout.web.tsx:59 +#: src/view/com/home/HomeHeaderLayout.web.tsx:62 #: src/view/screens/Feeds.tsx:355 msgid "Edit Saved Feeds" msgstr "Gespeicherte Feeds bearbeiten" #: src/view/com/modals/CreateOrEditList.tsx:245 msgid "Edit User List" -msgstr "" +msgstr "Benutzerliste bearbeiten" #: src/view/com/modals/EditProfile.tsx:193 msgid "Edit your display name" -msgstr "" +msgstr "Bearbeite deinen Anzeigenamen" #: src/view/com/modals/EditProfile.tsx:211 msgid "Edit your profile description" -msgstr "" +msgstr "Bearbeite deine Profilbeschreibung" #: src/screens/Onboarding/index.tsx:34 msgid "Education" -msgstr "" +msgstr "Bildung" -#: src/view/com/auth/create/Step1.tsx:199 +#: src/view/com/auth/create/Step1.tsx:176 #: src/view/com/auth/login/ForgotPasswordForm.tsx:156 #: src/view/com/modals/ChangeEmail.tsx:141 -#: src/view/com/modals/Waitlist.tsx:88 msgid "Email" msgstr "E-Mail" -#: src/view/com/auth/create/Step1.tsx:190 +#: src/view/com/auth/create/Step1.tsx:167 #: src/view/com/auth/login/ForgotPasswordForm.tsx:147 msgid "Email address" msgstr "E-Mail-Adresse" @@ -1305,7 +1236,7 @@ msgstr "E-Mail-Adresse" #: src/view/com/modals/ChangeEmail.tsx:56 #: src/view/com/modals/ChangeEmail.tsx:88 msgid "Email updated" -msgstr "" +msgstr "E-Mail aktualisiert" #: src/view/com/modals/ChangeEmail.tsx:111 msgid "Email Updated" @@ -1313,7 +1244,7 @@ msgstr "E-Mail aktualisiert" #: src/view/com/modals/VerifyEmail.tsx:78 msgid "Email verified" -msgstr "" +msgstr "E-Mail verifiziert" #: src/view/screens/Settings/index.tsx:312 msgid "Email:" @@ -1321,24 +1252,24 @@ msgstr "E-Mail:" #: src/view/com/modals/EmbedConsent.tsx:113 msgid "Enable {0} only" -msgstr "" +msgstr "Nur {0} aktivieren" #: src/view/com/modals/ContentFilteringSettings.tsx:167 msgid "Enable Adult Content" -msgstr "" +msgstr "Inhalte für Erwachsene aktivieren" #: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:76 #: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:77 msgid "Enable adult content in your feeds" -msgstr "" +msgstr "Aktiviere Inhalte für Erwachsene in deinen Feeds" #: src/view/com/modals/EmbedConsent.tsx:97 msgid "Enable External Media" -msgstr "" +msgstr "Externe Medien aktivieren" #: src/view/screens/PreferencesExternalEmbeds.tsx:75 msgid "Enable media players for" -msgstr "" +msgstr "Aktiviere Medienplayer für" #: src/view/screens/PreferencesFollowingFeed.tsx:147 msgid "Enable this setting to only see replies between people you follow." @@ -1350,20 +1281,20 @@ msgstr "Ende des Feeds" #: src/view/com/modals/AddAppPasswords.tsx:166 msgid "Enter a name for this App Password" -msgstr "" +msgstr "Gebe einen Namen für dieses App-Passwort ein" -#: src/components/dialogs/MutedWords.tsx:87 -#: src/components/dialogs/MutedWords.tsx:88 +#: src/components/dialogs/MutedWords.tsx:100 +#: src/components/dialogs/MutedWords.tsx:101 msgid "Enter a word or tag" -msgstr "" +msgstr "Gib ein Wort oder einen Tag ein" #: src/view/com/modals/VerifyEmail.tsx:105 msgid "Enter Confirmation Code" -msgstr "" +msgstr "Bestätigungscode eingeben" #: src/view/com/modals/ChangePassword.tsx:151 msgid "Enter the code you received to change your password." -msgstr "" +msgstr "Gib den Code ein, welchen du erhalten hast, um dein Passwort zu ändern." #: src/view/com/modals/ChangeHandle.tsx:371 msgid "Enter the domain you want to use" @@ -1373,38 +1304,30 @@ msgstr "Gib die Domain ein, die du verwenden möchtest" msgid "Enter the email you used to create your account. We'll send you a \"reset code\" so you can set a new password." msgstr "Gib die E-Mail ein, die du zur Erstellung deines Kontos verwendet hast. Wir schicken dir einen \"Reset-Code\", damit du ein neues Passwort festlegen kannst." -#: src/view/com/auth/create/Step1.tsx:251 +#: src/view/com/auth/create/Step1.tsx:228 #: src/view/com/modals/BirthDateSettings.tsx:74 msgid "Enter your birth date" -msgstr "" +msgstr "Gib dein Geburtsdatum ein" -#: src/view/com/modals/Waitlist.tsx:78 -msgid "Enter your email" -msgstr "" - -#: src/view/com/auth/create/Step1.tsx:195 +#: src/view/com/auth/create/Step1.tsx:172 msgid "Enter your email address" msgstr "Gib deine E-Mail-Adresse ein" #: src/view/com/modals/ChangeEmail.tsx:41 msgid "Enter your new email above" -msgstr "" +msgstr "Gib oben deine neue E-Mail-Adresse ein" #: src/view/com/modals/ChangeEmail.tsx:117 msgid "Enter your new email address below." msgstr "Gib unten deine neue E-Mail-Adresse ein." -#: src/view/com/auth/create/Step2.tsx:188 -#~ msgid "Enter your phone number" -#~ msgstr "" - #: src/view/com/auth/login/Login.tsx:99 msgid "Enter your username and password" msgstr "Gib deinen Benutzernamen und dein Passwort ein" #: src/view/com/auth/create/Step3.tsx:67 msgid "Error receiving captcha response." -msgstr "" +msgstr "Fehler beim Empfang der Captcha-Antwort." #: src/view/screens/Search/Search.tsx:110 msgid "Error:" @@ -1416,20 +1339,16 @@ msgstr "Alle" #: src/view/com/modals/ChangeHandle.tsx:150 msgid "Exits handle change process" -msgstr "" +msgstr "Beendet den Prozess des Handle-Wechsels" #: src/view/com/lightbox/Lightbox.web.tsx:120 msgid "Exits image view" -msgstr "" +msgstr "Beendet die Bildansicht" #: src/view/com/modals/ListAddRemoveUsers.tsx:88 #: src/view/shell/desktop/Search.tsx:235 msgid "Exits inputting search query" -msgstr "" - -#: src/view/com/modals/Waitlist.tsx:138 -msgid "Exits signing up for waitlist with {email}" -msgstr "" +msgstr "Beendet die Eingabe der Suchanfrage" #: src/view/com/lightbox/Lightbox.web.tsx:163 msgid "Expand alt text" @@ -1438,76 +1357,72 @@ msgstr "Alt-Text erweitern" #: src/view/com/composer/ComposerReplyTo.tsx:81 #: src/view/com/composer/ComposerReplyTo.tsx:84 msgid "Expand or collapse the full post you are replying to" -msgstr "" +msgstr "Erweitere oder reduziere den gesamten Beitrag, auf den du antwortest" #: src/view/screens/Settings/index.tsx:753 msgid "Export my data" -msgstr "" +msgstr "Exportiere meine Daten" #: src/view/screens/Settings/ExportCarDialog.tsx:44 #: src/view/screens/Settings/index.tsx:764 msgid "Export My Data" -msgstr "" +msgstr "Exportiere meine Daten" #: src/view/com/modals/EmbedConsent.tsx:64 msgid "External Media" -msgstr "" +msgstr "Externe Medien" #: src/view/com/modals/EmbedConsent.tsx:75 #: src/view/screens/PreferencesExternalEmbeds.tsx:66 msgid "External media may allow websites to collect information about you and your device. No information is sent or requested until you press the \"play\" button." -msgstr "" +msgstr "Externe Medien können es Websites ermöglichen, Informationen über dich und dein Gerät zu sammeln. Es werden keine Informationen gesendet oder angefordert, bis du die Schaltfläche \"Abspielen\" drückst." -#: src/Navigation.tsx:261 +#: src/Navigation.tsx:263 #: src/view/screens/PreferencesExternalEmbeds.tsx:52 #: src/view/screens/Settings/index.tsx:657 msgid "External Media Preferences" -msgstr "" +msgstr "Externe Medienpräferenzen" #: src/view/screens/Settings/index.tsx:648 msgid "External media settings" -msgstr "" +msgstr "Externe Medienpräferenzen" #: src/view/com/modals/AddAppPasswords.tsx:115 #: src/view/com/modals/AddAppPasswords.tsx:119 msgid "Failed to create app password." -msgstr "" +msgstr "Das App-Passwort konnte nicht erstellt werden." #: src/view/com/modals/CreateOrEditList.tsx:206 msgid "Failed to create the list. Check your internet connection and try again." -msgstr "" +msgstr "Die Liste konnte nicht erstellt werden. Überprüfe deine Internetverbindung und versuche es erneut." -#: src/view/com/util/forms/PostDropdownBtn.tsx:110 +#: src/view/com/util/forms/PostDropdownBtn.tsx:128 msgid "Failed to delete post, please try again" -msgstr "" +msgstr "Beitrag konnte nicht gelöscht werden, bitte versuche es erneut" #: src/view/com/auth/onboarding/RecommendedFeeds.tsx:109 #: src/view/com/auth/onboarding/RecommendedFeeds.tsx:141 msgid "Failed to load recommended feeds" msgstr "Empfohlene Feeds konnten nicht geladen werden" -#: src/Navigation.tsx:192 +#: src/Navigation.tsx:194 msgid "Feed" -msgstr "" +msgstr "Feed" #: src/view/com/feeds/FeedSourceCard.tsx:231 msgid "Feed by {0}" -msgstr "" +msgstr "Feed von {0}" #: src/view/screens/Feeds.tsx:605 msgid "Feed offline" msgstr "Feed offline" -#: src/view/com/feeds/FeedPage.tsx:143 -#~ msgid "Feed Preferences" -#~ msgstr "Feed-Einstellungen" - #: src/view/shell/desktop/RightNav.tsx:61 #: src/view/shell/Drawer.tsx:311 msgid "Feedback" msgstr "Feedback" -#: src/Navigation.tsx:445 +#: src/Navigation.tsx:452 #: src/view/screens/Feeds.tsx:419 #: src/view/screens/Feeds.tsx:524 #: src/view/screens/Profile.tsx:184 @@ -1518,14 +1433,6 @@ msgstr "Feedback" msgid "Feeds" msgstr "Feeds" -#: src/screens/Onboarding/StepAlgoFeeds/index.tsx:106 -#~ msgid "Feeds are created by users and can give you entirely new experiences." -#~ msgstr "" - -#: src/screens/Onboarding/StepAlgoFeeds/index.tsx:106 -#~ msgid "Feeds are created by users and organizations. They offer you varied experiences and suggest content you may like using algorithms." -#~ msgstr "" - #: src/view/com/auth/onboarding/RecommendedFeeds.tsx:57 msgid "Feeds are created by users to curate content. Choose some feeds that you find interesting." msgstr "Feeds werden von Nutzern erstellt, um Inhalte zu kuratieren. Wähle einige Feeds aus, die du interessant findest." @@ -1536,17 +1443,17 @@ msgstr "Feeds sind benutzerdefinierte Algorithmen, die Nutzer mit ein wenig Prog #: src/screens/Onboarding/StepTopicalFeeds.tsx:76 msgid "Feeds can be topical as well!" -msgstr "" +msgstr "Die Feeds können auch auf einem Thema basieren!" #: src/screens/Onboarding/StepFinished.tsx:151 msgid "Finalizing" -msgstr "" +msgstr "Abschließen" #: src/view/com/posts/CustomFeedEmptyState.tsx:47 #: src/view/com/posts/FollowingEmptyState.tsx:57 #: src/view/com/posts/FollowingEndOfFeed.tsx:58 msgid "Find accounts to follow" -msgstr "" +msgstr "Konten zum Folgen finden" #: src/view/screens/Search/Search.tsx:440 msgid "Find users on Bluesky" @@ -1562,32 +1469,28 @@ msgstr "Suche nach ähnlichen Konten..." #: src/view/screens/PreferencesFollowingFeed.tsx:111 msgid "Fine-tune the content you see on your Following feed." -msgstr "" - -#: src/view/screens/PreferencesHomeFeed.tsx:111 -#~ msgid "Fine-tune the content you see on your home screen." -#~ msgstr "" +msgstr "Passe die Inhalte auf Deinem Following-Feed an." #: src/view/screens/PreferencesThreads.tsx:60 msgid "Fine-tune the discussion threads." -msgstr "" +msgstr "Passe die Diskussionsstränge an." #: src/screens/Onboarding/index.tsx:38 msgid "Fitness" -msgstr "" +msgstr "Fitness" #: src/screens/Onboarding/StepFinished.tsx:131 msgid "Flexible" -msgstr "" +msgstr "Flexibel" #: src/view/com/modals/EditImage.tsx:115 msgid "Flip horizontal" -msgstr "" +msgstr "Horizontal drehen" #: src/view/com/modals/EditImage.tsx:120 #: src/view/com/modals/EditImage.tsx:287 msgid "Flip vertically" -msgstr "" +msgstr "Vertikal drehen" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:181 #: src/view/com/post-thread/PostThreadFollowBtn.tsx:136 @@ -1598,21 +1501,21 @@ msgstr "Folgen" #: src/view/com/profile/FollowButton.tsx:64 msgctxt "action" msgid "Follow" -msgstr "" +msgstr "Folgen" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:58 #: src/view/com/post-thread/PostThreadFollowBtn.tsx:122 #: src/view/com/profile/ProfileHeader.tsx:504 msgid "Follow {0}" -msgstr "" +msgstr "{0} folgen" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:179 msgid "Follow All" -msgstr "" +msgstr "Allen folgen" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:174 msgid "Follow selected accounts and continue to the next step" -msgstr "" +msgstr "Ausgewählten Konten folgen und mit dem nächsten Schritt fortfahren" #: src/view/com/auth/onboarding/RecommendedFollows.tsx:64 msgid "Follow some users to get started. We can recommend you more users based on who you find interesting." @@ -1620,19 +1523,19 @@ msgstr "Folge einigen Nutzern, um loszulegen. Wir können dir weitere Nutzer emp #: src/view/com/profile/ProfileCard.tsx:194 msgid "Followed by {0}" -msgstr "" +msgstr "Gefolgt von {0}" #: src/view/com/modals/Threadgate.tsx:98 msgid "Followed users" -msgstr "" +msgstr "Benutzer, denen ich folge" #: src/view/screens/PreferencesFollowingFeed.tsx:154 msgid "Followed users only" -msgstr "" +msgstr "Nur Benutzer, denen ich folge" #: src/view/com/notifications/FeedItem.tsx:166 msgid "followed you" -msgstr "" +msgstr "folgte dir" #: src/view/screens/ProfileFollowers.tsx:25 msgid "Followers" @@ -1646,15 +1549,15 @@ msgstr "Folge ich" #: src/view/com/profile/ProfileHeader.tsx:149 msgid "Following {0}" -msgstr "" +msgstr "ich folge {0}" -#: src/Navigation.tsx:248 -#: src/view/com/home/HomeHeaderLayout.web.tsx:45 -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:83 +#: src/Navigation.tsx:250 +#: src/view/com/home/HomeHeaderLayout.web.tsx:50 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:84 #: src/view/screens/PreferencesFollowingFeed.tsx:104 #: src/view/screens/Settings/index.tsx:543 msgid "Following Feed Preferences" -msgstr "" +msgstr "Following-Feed-Einstellungen" #: src/view/com/profile/ProfileHeader.tsx:546 msgid "Follows you" @@ -1662,11 +1565,11 @@ msgstr "Folgt dir" #: src/view/com/profile/ProfileCard.tsx:141 msgid "Follows You" -msgstr "" +msgstr "Folgt dir" #: src/screens/Onboarding/index.tsx:43 msgid "Food" -msgstr "" +msgstr "Essen" #: src/view/com/modals/DeleteAccount.tsx:111 msgid "For security reasons, we'll need to send a confirmation code to your email address." @@ -1689,10 +1592,15 @@ msgstr "Passwort vergessen" msgid "Forgot Password" msgstr "Passwort vergessen" +#: src/screens/Hashtag.tsx:108 +#: src/screens/Hashtag.tsx:148 +msgid "From @{sanitizedAuthor}" +msgstr "Von @{sanitizedAuthor}" + #: src/view/com/posts/FeedItem.tsx:189 msgctxt "from-feed" msgid "From <0/>" -msgstr "" +msgstr "Aus <0/>" #: src/view/com/composer/photos/SelectPhotoBtn.tsx:43 msgid "Gallery" @@ -1712,20 +1620,20 @@ msgstr "Gehe zurück" #: src/view/screens/ProfileFeed.tsx:106 #: src/view/screens/ProfileFeed.tsx:111 -#: src/view/screens/ProfileList.tsx:897 #: src/view/screens/ProfileList.tsx:902 +#: src/view/screens/ProfileList.tsx:907 msgid "Go Back" msgstr "Gehe zurück" #: src/screens/Onboarding/Layout.tsx:104 #: src/screens/Onboarding/Layout.tsx:193 msgid "Go back to previous step" -msgstr "" +msgstr "Zum vorherigen Schritt zurückkehren" #: src/view/screens/Search/Search.tsx:747 #: src/view/shell/desktop/Search.tsx:262 msgid "Go to @{queryMaybeHandle}" -msgstr "" +msgstr "Gehe zu @{queryMaybeHandle}" #: src/view/com/auth/login/ForgotPasswordForm.tsx:189 #: src/view/com/auth/login/ForgotPasswordForm.tsx:218 @@ -1739,13 +1647,17 @@ msgstr "Gehe zum nächsten" msgid "Handle" msgstr "Handle" -#: src/components/RichText.tsx:188 -msgid "Hashtag: {tag}" -msgstr "" +#: src/Navigation.tsx:270 +msgid "Hashtag" +msgstr "Hashtag" + +#: src/components/RichText.tsx:190 +msgid "Hashtag: #{tag}" +msgstr "Hashtag: #{tag}" #: src/view/com/auth/create/CreateAccount.tsx:208 msgid "Having trouble?" -msgstr "" +msgstr "Hast du Probleme?" #: src/view/shell/desktop/RightNav.tsx:90 #: src/view/shell/Drawer.tsx:321 @@ -1754,15 +1666,15 @@ msgstr "Hilfe" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:132 msgid "Here are some accounts for you to follow" -msgstr "" +msgstr "Hier sind einige Konten, denen du folgen könntest" #: src/screens/Onboarding/StepTopicalFeeds.tsx:85 msgid "Here are some popular topical feeds. You can choose to follow as many as you like." -msgstr "" +msgstr "Hier sind einige beliebte thematische Feeds. Du kannst so vielen folgen, wie du möchtest." #: src/screens/Onboarding/StepTopicalFeeds.tsx:80 msgid "Here are some topical feeds based on your interests: {interestsText}. You can choose to follow as many as you like." -msgstr "" +msgstr "Hier sind einige thematische Feeds, die auf deinen Interessen basieren: {interestsText}. Du kannst so vielen Feeds folgen, wie du möchtest." #: src/view/com/modals/AddAppPasswords.tsx:153 msgid "Here is your app password." @@ -1776,43 +1688,44 @@ msgid "Hide" msgstr "Ausblenden" #: src/view/com/modals/ContentFilteringSettings.tsx:224 -#: src/view/com/notifications/FeedItem.tsx:325 +#: src/view/com/notifications/FeedItem.tsx:326 msgctxt "action" msgid "Hide" -msgstr "" +msgstr "Ausblenden" -#: src/view/com/util/forms/PostDropdownBtn.tsx:232 +#: src/view/com/util/forms/PostDropdownBtn.tsx:276 +#: src/view/com/util/forms/PostDropdownBtn.tsx:287 msgid "Hide post" msgstr "Beitrag ausblenden" #: src/view/com/util/moderation/ContentHider.tsx:67 #: src/view/com/util/moderation/PostHider.tsx:61 msgid "Hide the content" -msgstr "" +msgstr "Den Inhalt ausblenden" -#: src/view/com/util/forms/PostDropdownBtn.tsx:236 +#: src/view/com/util/forms/PostDropdownBtn.tsx:280 msgid "Hide this post?" msgstr "Diesen Beitrag ausblenden?" -#: src/view/com/notifications/FeedItem.tsx:315 +#: src/view/com/notifications/FeedItem.tsx:316 msgid "Hide user list" msgstr "Benutzerliste ausblenden" #: src/view/com/profile/ProfileHeader.tsx:487 msgid "Hides posts from {0} in your feed" -msgstr "" +msgstr "Blendet Beiträge von {0} in Deinem Feed aus" #: src/view/com/posts/FeedErrorMessage.tsx:111 msgid "Hmm, some kind of issue occurred when contacting the feed server. Please let the feed owner know about this issue." -msgstr "Hm, beim Kontakt mit dem Feed-Server ist ein Problem aufgetreten. Bitte informiere den Eigentümer des Feeds über dieses Problem." +msgstr "Hmm, beim Kontakt mit dem Feed-Server ist ein Problem aufgetreten. Bitte informiere den Eigentümer des Feeds über dieses Problem." #: src/view/com/posts/FeedErrorMessage.tsx:99 msgid "Hmm, the feed server appears to be misconfigured. Please let the feed owner know about this issue." -msgstr "Hm, der Feed-Server scheint falsch konfiguriert zu sein. Bitte informiere den Eigentümer des Feeds über dieses Problem." +msgstr "Hmm, der Feed-Server scheint falsch konfiguriert zu sein. Bitte informiere den Eigentümer des Feeds über dieses Problem." #: src/view/com/posts/FeedErrorMessage.tsx:105 msgid "Hmm, the feed server appears to be offline. Please let the feed owner know about this issue." -msgstr "Hm, der Feed-Server scheint offline zu sein. Bitte informiere den Eigentümer des Feeds über dieses Problem." +msgstr "Hmm, der Feed-Server scheint offline zu sein. Bitte informiere den Eigentümer des Feeds über dieses Problem." #: src/view/com/posts/FeedErrorMessage.tsx:102 msgid "Hmm, the feed server gave a bad response. Please let the feed owner know about this issue." @@ -1820,9 +1733,9 @@ msgstr "Hmm, der Feed-Server hat eine schlechte Antwort gegeben. Bitte informier #: src/view/com/posts/FeedErrorMessage.tsx:96 msgid "Hmm, we're having trouble finding this feed. It may have been deleted." -msgstr "Hm, wir haben Probleme, diesen Feed zu finden. Möglicherweise wurde er gelöscht." +msgstr "Hmm, wir haben Probleme, diesen Feed zu finden. Möglicherweise wurde er gelöscht." -#: src/Navigation.tsx:435 +#: src/Navigation.tsx:442 #: src/view/shell/bottom-bar/BottomBar.tsx:137 #: src/view/shell/desktop/LeftNav.tsx:306 #: src/view/shell/Drawer.tsx:398 @@ -1830,21 +1743,14 @@ msgstr "Hm, wir haben Probleme, diesen Feed zu finden. Möglicherweise wurde er msgid "Home" msgstr "Home" -#: src/Navigation.tsx:247 -#: src/view/com/pager/FeedsTabBarMobile.tsx:123 -#: src/view/screens/PreferencesHomeFeed.tsx:104 -#: src/view/screens/Settings/index.tsx:543 -#~ msgid "Home Feed Preferences" -#~ msgstr "Home-Feed-Einstellungen" - -#: src/view/com/auth/create/Step1.tsx:82 +#: src/view/com/auth/create/Step1.tsx:75 #: src/view/com/auth/login/ForgotPasswordForm.tsx:120 msgid "Hosting provider" msgstr "Hosting-Anbieter" #: src/view/com/modals/InAppBrowserConsent.tsx:44 msgid "How should we open this link?" -msgstr "" +msgstr "Wie sollen wir diesen Link öffnen?" #: src/view/com/modals/VerifyEmail.tsx:214 msgid "I have a code" @@ -1852,7 +1758,7 @@ msgstr "Ich habe einen Code" #: src/view/com/modals/VerifyEmail.tsx:216 msgid "I have a confirmation code" -msgstr "" +msgstr "Ich habe einen Bestätigungscode" #: src/view/com/modals/ChangeHandle.tsx:283 msgid "I have my own domain" @@ -1860,7 +1766,7 @@ msgstr "Ich habe meine eigene Domain" #: src/view/com/lightbox/Lightbox.web.tsx:165 msgid "If alt text is long, toggles alt text expanded state" -msgstr "" +msgstr "Schaltet den erweiterten Status des Alt-Textes um, wenn dieser lang ist" #: src/view/com/modals/SelfLabel.tsx:127 msgid "If none are selected, suitable for all ages." @@ -1868,11 +1774,11 @@ msgstr "Wenn keine ausgewählt werden, sind sie für alle Altersgruppen geeignet #: src/view/com/modals/ChangePassword.tsx:146 msgid "If you want to change your password, we will send you a code to verify that this is your account." -msgstr "" +msgstr "Wenn du dein Passwort ändern möchtest, senden wir dir einen Code, um zu bestätigen, dass es sich um dein Konto handelt." #: src/view/com/util/images/Gallery.tsx:38 msgid "Image" -msgstr "" +msgstr "Bild" #: src/view/com/modals/AltImage.tsx:120 msgid "Image alt text" @@ -1885,78 +1791,62 @@ msgstr "Bild-Optionen" #: src/view/com/auth/login/SetNewPasswordForm.tsx:138 msgid "Input code sent to your email for password reset" -msgstr "" +msgstr "Gib den Code ein, den du per E-Mail erhalten hast, um dein Passwort zurückzusetzen." #: src/view/com/modals/DeleteAccount.tsx:184 msgid "Input confirmation code for account deletion" -msgstr "" +msgstr "Bestätigungscode für die Kontolöschung eingeben" -#: src/view/com/auth/create/Step1.tsx:200 +#: src/view/com/auth/create/Step1.tsx:177 msgid "Input email for Bluesky account" -msgstr "" +msgstr "E-Mail für Bluesky-Konto eingeben" -#: src/view/com/auth/create/Step1.tsx:158 +#: src/view/com/auth/create/Step1.tsx:151 msgid "Input invite code to proceed" -msgstr "" +msgstr "Einladungscode eingeben, um fortzufahren" #: src/view/com/modals/AddAppPasswords.tsx:180 msgid "Input name for app password" -msgstr "" +msgstr "Namen für das App-Passwort eingeben" #: src/view/com/auth/login/SetNewPasswordForm.tsx:162 msgid "Input new password" -msgstr "" +msgstr "Neues Passwort eingeben" #: src/view/com/modals/DeleteAccount.tsx:203 msgid "Input password for account deletion" -msgstr "" - -#: src/view/com/auth/create/Step2.tsx:196 -#~ msgid "Input phone number for SMS verification" -#~ msgstr "" +msgstr "Passwort für die Kontolöschung eingeben" #: src/view/com/auth/login/LoginForm.tsx:230 msgid "Input the password tied to {identifier}" -msgstr "" +msgstr "Passwort, das an {identifier} gebunden ist, eingeben" #: src/view/com/auth/login/LoginForm.tsx:197 msgid "Input the username or email address you used at signup" -msgstr "" - -#: src/view/com/auth/create/Step2.tsx:271 -#~ msgid "Input the verification code we have texted to you" -#~ msgstr "" - -#: src/view/com/modals/Waitlist.tsx:90 -msgid "Input your email to get on the Bluesky waitlist" -msgstr "" +msgstr "Benutzernamen oder E-Mail-Adresse eingeben, die du bei der Anmeldung verwendet hast" #: src/view/com/auth/login/LoginForm.tsx:229 msgid "Input your password" -msgstr "" +msgstr "Gib dein Passwort ein" #: src/view/com/auth/create/Step2.tsx:80 msgid "Input your user handle" -msgstr "" +msgstr "Gib deinen Handle ein" #: src/view/com/post-thread/PostThreadItem.tsx:226 msgid "Invalid or unsupported post record" -msgstr "" +msgstr "Ungültiger oder nicht unterstützter Beitragrekord" #: src/view/com/auth/login/LoginForm.tsx:113 msgid "Invalid username or password" msgstr "Ungültiger Benutzername oder Passwort" -#: src/view/screens/Settings.tsx:411 -#~ msgid "Invite" -#~ msgstr "Einladen" - #: src/view/com/modals/InviteCodes.tsx:93 msgid "Invite a Friend" msgstr "Einen Freund einladen" -#: src/view/com/auth/create/Step1.tsx:148 -#: src/view/com/auth/create/Step1.tsx:157 +#: src/view/com/auth/create/Step1.tsx:141 +#: src/view/com/auth/create/Step1.tsx:150 msgid "Invite code" msgstr "Einladungscode" @@ -1966,41 +1856,24 @@ msgstr "Einladungscode nicht akzeptiert. Überprüfe, ob du ihn richtig eingegeb #: src/view/com/modals/InviteCodes.tsx:170 msgid "Invite codes: {0} available" -msgstr "" - -#: src/view/shell/Drawer.tsx:645 -#~ msgid "Invite codes: {invitesAvailable} available" -#~ msgstr "Einladungscodes: {invitesAvailable} verfügbar" +msgstr "Einladungscodes: {0} verfügbar" #: src/view/com/modals/InviteCodes.tsx:169 msgid "Invite codes: 1 available" -msgstr "" +msgstr "Einladungscodes: 1 verfügbar" #: src/screens/Onboarding/StepFollowingFeed.tsx:64 msgid "It shows posts from the people you follow as they happen." -msgstr "" +msgstr "Es zeigt die Beiträge der Personen an, denen du folgst, sobald sie erscheinen." #: src/view/com/auth/HomeLoggedOutCTA.tsx:99 #: src/view/com/auth/SplashScreen.web.tsx:138 msgid "Jobs" msgstr "Jobs" -#: src/view/com/modals/Waitlist.tsx:67 -msgid "Join the waitlist" -msgstr "Der Warteliste beitreten" - -#: src/view/com/auth/create/Step1.tsx:174 -#: src/view/com/auth/create/Step1.tsx:178 -msgid "Join the waitlist." -msgstr "Der Warteliste beitreten." - -#: src/view/com/modals/Waitlist.tsx:128 -msgid "Join Waitlist" -msgstr "Warteliste beitreten" - #: src/screens/Onboarding/index.tsx:24 msgid "Journalism" -msgstr "" +msgstr "Journalismus" #: src/view/com/composer/select-language/SelectLangBtn.tsx:104 msgid "Language selection" @@ -2008,9 +1881,9 @@ msgstr "Sprachauswahl" #: src/view/screens/Settings/index.tsx:594 msgid "Language settings" -msgstr "" +msgstr "Spracheinstellungen" -#: src/Navigation.tsx:140 +#: src/Navigation.tsx:142 #: src/view/screens/LanguageSettings.tsx:89 msgid "Language Settings" msgstr "Spracheinstellungen" @@ -2021,7 +1894,7 @@ msgstr "Sprachen" #: src/view/com/auth/create/StepHeader.tsx:20 msgid "Last step!" -msgstr "" +msgstr "Letzter Schritt!" #: src/view/com/util/moderation/ContentHider.tsx:103 msgid "Learn more" @@ -2055,11 +1928,11 @@ msgstr "Bluesky verlassen" #: src/screens/Deactivated.tsx:128 msgid "left to go." -msgstr "" +msgstr "noch übrig." #: src/view/screens/Settings/index.tsx:278 msgid "Legacy storage cleared, you need to restart the app now." -msgstr "" +msgstr "Der Legacy-Speicher wurde gelöscht, du musst die App jetzt neu starten." #: src/view/com/auth/login/Login.tsx:128 #: src/view/com/auth/login/Login.tsx:144 @@ -2068,7 +1941,7 @@ msgstr "Lass uns dein Passwort zurücksetzen!" #: src/screens/Onboarding/StepFinished.tsx:151 msgid "Let's go!" -msgstr "" +msgstr "Los geht's!" #: src/view/com/util/UserAvatar.tsx:248 #: src/view/com/util/UserBanner.tsx:62 @@ -2077,87 +1950,86 @@ msgstr "Bibliothek" #: src/view/screens/Settings/index.tsx:479 msgid "Light" -msgstr "" +msgstr "Licht" #: src/view/com/util/post-ctrls/PostCtrls.tsx:182 -#: src/view/com/util/post-ctrls/PostCtrls.tsx:216 msgid "Like" -msgstr "" +msgstr "Liken" #: src/view/screens/ProfileFeed.tsx:591 msgid "Like this feed" -msgstr "" +msgstr "Diesen Feed liken" -#: src/Navigation.tsx:197 +#: src/Navigation.tsx:199 msgid "Liked by" -msgstr "" +msgstr "Gelikt von" #: src/view/screens/PostLikedBy.tsx:27 #: src/view/screens/ProfileFeedLikedBy.tsx:27 msgid "Liked By" -msgstr "" +msgstr "Gelikt von" #: src/view/com/feeds/FeedSourceCard.tsx:279 msgid "Liked by {0} {1}" -msgstr "" +msgstr "Von {0} {1} gelikt" #: src/view/screens/ProfileFeed.tsx:606 msgid "Liked by {likeCount} {0}" -msgstr "" +msgstr "Von {likeCount} {0} gelikt" #: src/view/com/notifications/FeedItem.tsx:170 msgid "liked your custom feed" -msgstr "" +msgstr "hat deinen benutzerdefinierten Feed gelikt" #: src/view/com/notifications/FeedItem.tsx:155 msgid "liked your post" -msgstr "" +msgstr "hat deinen Beitrag gelikt" #: src/view/screens/Profile.tsx:183 msgid "Likes" -msgstr "" +msgstr "Likes" #: src/view/com/post-thread/PostThreadItem.tsx:183 msgid "Likes on this post" -msgstr "" +msgstr "Likes für diesen Beitrag" -#: src/Navigation.tsx:166 +#: src/Navigation.tsx:168 msgid "List" -msgstr "" +msgstr "Liste" #: src/view/com/modals/CreateOrEditList.tsx:261 msgid "List Avatar" -msgstr "" +msgstr "Avatar auflisten" #: src/view/screens/ProfileList.tsx:324 msgid "List blocked" -msgstr "" +msgstr "Liste blockiert" #: src/view/com/feeds/FeedSourceCard.tsx:233 msgid "List by {0}" -msgstr "" +msgstr "Liste von {0}" #: src/view/screens/ProfileList.tsx:378 msgid "List deleted" -msgstr "" +msgstr "Liste gelöscht" #: src/view/screens/ProfileList.tsx:283 msgid "List muted" -msgstr "" +msgstr "Liste stummgeschaltet" #: src/view/com/modals/CreateOrEditList.tsx:275 msgid "List Name" -msgstr "" +msgstr "Name der Liste" #: src/view/screens/ProfileList.tsx:343 msgid "List unblocked" -msgstr "" +msgstr "Liste entblockiert" #: src/view/screens/ProfileList.tsx:302 msgid "List unmuted" -msgstr "" +msgstr "Listenstummschaltung aufgehoben" -#: src/Navigation.tsx:110 +#: src/Navigation.tsx:112 #: src/view/screens/Profile.tsx:185 #: src/view/shell/desktop/LeftNav.tsx:379 #: src/view/shell/Drawer.tsx:492 @@ -2172,7 +2044,7 @@ msgstr "Mehr Beiträge laden" #: src/view/screens/Notifications.tsx:159 msgid "Load new notifications" -msgstr "Neue Benachrichtigungen laden" +msgstr "Neue Mitteilungen laden" #: src/view/com/feeds/FeedPage.tsx:115 #: src/view/screens/Profile.tsx:440 @@ -2185,24 +2057,20 @@ msgstr "Neue Beiträge laden" msgid "Loading..." msgstr "Wird geladen..." -#: src/view/com/modals/ServerInput.tsx:50 -#~ msgid "Local dev server" -#~ msgstr "Lokaler Entwicklungsserver" - -#: src/Navigation.tsx:207 +#: src/Navigation.tsx:209 msgid "Log" -msgstr "" +msgstr "Systemprotokoll" #: src/screens/Deactivated.tsx:149 #: src/screens/Deactivated.tsx:152 #: src/screens/Deactivated.tsx:178 #: src/screens/Deactivated.tsx:181 msgid "Log out" -msgstr "" +msgstr "Abmelden" #: src/view/screens/Moderation.tsx:155 msgid "Logged-out visibility" -msgstr "" +msgstr "Sichtbarkeit für abgemeldete Benutzer" #: src/view/com/auth/login/ChooseAccountForm.tsx:133 msgid "Login to account that is not listed" @@ -2212,17 +2080,17 @@ msgstr "Anmeldung bei einem Konto, das nicht aufgelistet ist" msgid "Make sure this is where you intend to go!" msgstr "Vergewissere dich, dass du auch wirklich dorthin gehen willst!" -#: src/components/dialogs/MutedWords.tsx:71 +#: src/components/dialogs/MutedWords.tsx:83 msgid "Manage your muted words and tags" -msgstr "" +msgstr "Verwalte deine stummgeschalteten Wörter und Tags" #: src/view/com/auth/create/Step2.tsx:118 msgid "May not be longer than 253 characters" -msgstr "" +msgstr "Darf nicht länger als 253 Zeichen sein" #: src/view/com/auth/create/Step2.tsx:109 msgid "May only contain letters and numbers" -msgstr "" +msgstr "Darf nur Buchstaben und Zahlen enthalten" #: src/view/screens/Profile.tsx:182 msgid "Media" @@ -2236,7 +2104,7 @@ msgstr "erwähnte Benutzer" msgid "Mentioned users" msgstr "Erwähnte Benutzer" -#: src/view/com/util/ViewHeader.tsx:81 +#: src/view/com/util/ViewHeader.tsx:87 #: src/view/screens/Search/Search.tsx:646 msgid "Menu" msgstr "Menü" @@ -2245,7 +2113,7 @@ msgstr "Menü" msgid "Message from server: {0}" msgstr "Nachricht vom Server: {0}" -#: src/Navigation.tsx:115 +#: src/Navigation.tsx:117 #: src/view/screens/Moderation.tsx:66 #: src/view/screens/Settings/index.tsx:625 #: src/view/shell/desktop/LeftNav.tsx:397 @@ -2257,44 +2125,44 @@ msgstr "Moderation" #: src/view/com/lists/ListCard.tsx:93 #: src/view/com/modals/UserAddRemoveLists.tsx:206 msgid "Moderation list by {0}" -msgstr "" +msgstr "Moderationsliste von {0}" -#: src/view/screens/ProfileList.tsx:774 +#: src/view/screens/ProfileList.tsx:775 msgid "Moderation list by <0/>" -msgstr "" +msgstr "Moderationsliste von <0/>" #: src/view/com/lists/ListCard.tsx:91 #: src/view/com/modals/UserAddRemoveLists.tsx:204 -#: src/view/screens/ProfileList.tsx:772 +#: src/view/screens/ProfileList.tsx:773 msgid "Moderation list by you" -msgstr "" +msgstr "Moderationsliste von dir" #: src/view/com/modals/CreateOrEditList.tsx:197 msgid "Moderation list created" -msgstr "" +msgstr "Moderationsliste erstellt" #: src/view/com/modals/CreateOrEditList.tsx:183 msgid "Moderation list updated" -msgstr "" +msgstr "Moderationsliste aktualisiert" #: src/view/screens/Moderation.tsx:114 msgid "Moderation lists" msgstr "Moderationslisten" -#: src/Navigation.tsx:120 +#: src/Navigation.tsx:122 #: src/view/screens/ModerationModlists.tsx:58 msgid "Moderation Lists" msgstr "Moderationslisten" #: src/view/screens/Settings/index.tsx:619 msgid "Moderation settings" -msgstr "" +msgstr "Moderationseinstellungen" #: src/view/com/modals/ModerationDetails.tsx:35 msgid "Moderator has chosen to set a general warning on the content." -msgstr "" +msgstr "Der Moderator hat beschlossen, eine allgemeine Warnung vor dem Inhalt auszusprechen." -#: src/view/shell/desktop/Feeds.tsx:63 +#: src/view/shell/desktop/Feeds.tsx:65 msgid "More feeds" msgstr "Mehr Feeds" @@ -2304,25 +2172,21 @@ msgstr "Mehr Feeds" msgid "More options" msgstr "Mehr Optionen" -#: src/view/com/util/forms/PostDropdownBtn.tsx:315 -msgid "More post options" -msgstr "" - #: src/view/screens/PreferencesThreads.tsx:82 msgid "Most-liked replies first" -msgstr "" +msgstr "Beliebteste Antworten zuerst" #: src/view/com/auth/create/Step2.tsx:122 msgid "Must be at least 3 characters" -msgstr "" +msgstr "Muss mindestens 3 Zeichen lang sein" -#: src/components/TagMenu/index.tsx:253 +#: src/components/TagMenu/index.tsx:249 msgid "Mute" -msgstr "" +msgstr "Stummschalten" -#: src/components/TagMenu/index.web.tsx:91 +#: src/components/TagMenu/index.web.tsx:105 msgid "Mute {truncatedTag}" -msgstr "" +msgstr "{truncatedTag} stummschalten" #: src/view/com/profile/ProfileHeader.tsx:327 msgid "Mute Account" @@ -2332,21 +2196,21 @@ msgstr "Konto stummschalten" msgid "Mute accounts" msgstr "Konten stummschalten" -#: src/components/TagMenu/index.tsx:211 -msgid "Mute all {tag} posts" -msgstr "" +#: src/components/TagMenu/index.tsx:209 +msgid "Mute all {displayTag} posts" +msgstr "Alle {displayTag}-Beiträge stummschalten" -#: src/components/dialogs/MutedWords.tsx:131 +#: src/components/dialogs/MutedWords.tsx:149 msgid "Mute in tags only" -msgstr "" +msgstr "Nur in Tags stummschalten" -#: src/components/dialogs/MutedWords.tsx:116 +#: src/components/dialogs/MutedWords.tsx:134 msgid "Mute in text & tags" -msgstr "" +msgstr "In Text und Tags stummschalten" #: src/view/screens/ProfileList.tsx:491 msgid "Mute list" -msgstr "" +msgstr "Liste stummschalten" #: src/view/screens/ProfileList.tsx:275 msgid "Mute these accounts?" @@ -2354,48 +2218,50 @@ msgstr "Diese Konten stummschalten?" #: src/view/screens/ProfileList.tsx:279 msgid "Mute this List" -msgstr "" +msgstr "Diese Liste stummschalten" -#: src/components/dialogs/MutedWords.tsx:109 +#: src/components/dialogs/MutedWords.tsx:127 msgid "Mute this word in post text and tags" -msgstr "" +msgstr "Dieses Wort in Beitragstexten und Tags stummschalten" -#: src/components/dialogs/MutedWords.tsx:124 +#: src/components/dialogs/MutedWords.tsx:142 msgid "Mute this word in tags only" -msgstr "" +msgstr "Dieses Wort nur in Tags stummschalten" -#: src/view/com/util/forms/PostDropdownBtn.tsx:202 +#: src/view/com/util/forms/PostDropdownBtn.tsx:251 +#: src/view/com/util/forms/PostDropdownBtn.tsx:257 msgid "Mute thread" msgstr "Thread stummschalten" -#: src/view/com/util/forms/PostDropdownBtn.tsx:216 +#: src/view/com/util/forms/PostDropdownBtn.tsx:267 +#: src/view/com/util/forms/PostDropdownBtn.tsx:269 msgid "Mute words & tags" -msgstr "" +msgstr "Wörter und Tags stummschalten" #: src/view/com/lists/ListCard.tsx:102 msgid "Muted" -msgstr "" +msgstr "Stummgeschaltet" #: src/view/screens/Moderation.tsx:128 msgid "Muted accounts" msgstr "Stummgeschaltete Konten" -#: src/Navigation.tsx:125 +#: src/Navigation.tsx:127 #: src/view/screens/ModerationMutedAccounts.tsx:107 msgid "Muted Accounts" msgstr "Stummgeschaltete Konten" #: src/view/screens/ModerationMutedAccounts.tsx:115 msgid "Muted accounts have their posts removed from your feed and from your notifications. Mutes are completely private." -msgstr "Bei stummgeschalteten Konten werden ihre Beiträge aus deinem Feed und deinen Benachrichtigungen entfernt. Stummschaltungen sind völlig privat." +msgstr "Bei stummgeschalteten Konten werden dazugehörige Beiträge aus deinem Feed und deinen Mitteilungen entfernt. Stummschaltungen sind völlig privat." #: src/view/screens/Moderation.tsx:100 msgid "Muted words & tags" -msgstr "" +msgstr "Stummgeschaltete Wörter und Tags" #: src/view/screens/ProfileList.tsx:277 msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them." -msgstr "Stummschaltung ist privat. Stummgeschaltete Konten können mit dir interagieren, aber du siehst ihre Beiträge nicht und erhältst keine Benachrichtigungen von ihnen." +msgstr "Stummschaltung ist privat. Stummgeschaltete Konten können mit dir interagieren, aber du siehst ihre Beiträge nicht und erhältst keine Mitteilungen von ihnen." #: src/view/com/modals/BirthDateSettings.tsx:56 msgid "My Birthday" @@ -2415,7 +2281,7 @@ msgstr "Meine gespeicherten Feeds" #: src/view/com/auth/server-input/index.tsx:118 msgid "my-server.com" -msgstr "" +msgstr "mein-server.de" #: src/view/com/modals/AddAppPasswords.tsx:179 #: src/view/com/modals/CreateOrEditList.tsx:290 @@ -2424,11 +2290,11 @@ msgstr "Name" #: src/view/com/modals/CreateOrEditList.tsx:145 msgid "Name is required" -msgstr "" +msgstr "Name ist erforderlich" #: src/screens/Onboarding/index.tsx:25 msgid "Nature" -msgstr "" +msgstr "Natur" #: src/view/com/auth/login/ForgotPasswordForm.tsx:190 #: src/view/com/auth/login/ForgotPasswordForm.tsx:219 @@ -2436,16 +2302,16 @@ msgstr "" #: src/view/com/auth/login/SetNewPasswordForm.tsx:196 #: src/view/com/modals/ChangePassword.tsx:166 msgid "Navigates to the next screen" -msgstr "" +msgstr "Navigiert zum nächsten Bildschirm" #: src/view/shell/Drawer.tsx:71 msgid "Navigates to your profile" -msgstr "" +msgstr "Navigiert zu Deinem Profil" #: src/view/com/modals/EmbedConsent.tsx:107 #: src/view/com/modals/EmbedConsent.tsx:123 msgid "Never load embeds from {0}" -msgstr "" +msgstr "Lade niemals eingebettete Medien von {0}" #: src/view/com/auth/onboarding/WelcomeDesktop.tsx:72 #: src/view/com/auth/onboarding/WelcomeMobile.tsx:72 @@ -2454,16 +2320,16 @@ msgstr "Verliere nie den Zugriff auf deine Follower und Daten." #: src/screens/Onboarding/StepFinished.tsx:119 msgid "Never lose access to your followers or data." -msgstr "" +msgstr "Verliere nie den Zugriff auf deine Follower oder Daten." -#: src/components/dialogs/MutedWords.tsx:244 +#: src/components/dialogs/MutedWords.tsx:293 msgid "Nevermind" -msgstr "" +msgstr "Egal" #: src/view/screens/Lists.tsx:76 msgctxt "action" msgid "New" -msgstr "" +msgstr "Neu" #: src/view/screens/ModerationModlists.tsx:78 msgid "New" @@ -2471,20 +2337,20 @@ msgstr "Neu" #: src/view/com/modals/CreateOrEditList.tsx:252 msgid "New Moderation List" -msgstr "" +msgstr "Neue Moderationsliste" #: src/view/com/auth/login/SetNewPasswordForm.tsx:150 msgid "New password" -msgstr "" +msgstr "Neues Passwort" #: src/view/com/modals/ChangePassword.tsx:215 msgid "New Password" -msgstr "" +msgstr "Neues Passwort" #: src/view/com/feeds/FeedPage.tsx:126 msgctxt "action" msgid "New post" -msgstr "" +msgstr "Neuer Beitrag" #: src/view/screens/Feeds.tsx:555 #: src/view/screens/Notifications.tsx:168 @@ -2503,15 +2369,15 @@ msgstr "Neuer Beitrag" #: src/view/com/modals/CreateOrEditList.tsx:247 msgid "New User List" -msgstr "" +msgstr "Neue Benutzerliste" #: src/view/screens/PreferencesThreads.tsx:79 msgid "Newest replies first" -msgstr "" +msgstr "Neueste Antworten zuerst" #: src/screens/Onboarding/index.tsx:23 msgid "News" -msgstr "" +msgstr "Aktuelles" #: src/view/com/auth/create/CreateAccount.tsx:172 #: src/view/com/auth/login/ForgotPasswordForm.tsx:182 @@ -2528,7 +2394,7 @@ msgstr "Nächste" #: src/view/com/auth/onboarding/WelcomeDesktop.tsx:103 msgctxt "action" msgid "Next" -msgstr "" +msgstr "Nächste" #: src/view/com/lightbox/Lightbox.web.tsx:149 msgid "Next image" @@ -2544,23 +2410,27 @@ msgid "No" msgstr "Nein" #: src/view/screens/ProfileFeed.tsx:584 -#: src/view/screens/ProfileList.tsx:754 +#: src/view/screens/ProfileList.tsx:755 msgid "No description" msgstr "Keine Beschreibung" #: src/view/com/profile/ProfileHeader.tsx:170 msgid "No longer following {0}" -msgstr "" +msgstr "{0} wird nicht mehr gefolgt" #: src/view/com/notifications/Feed.tsx:109 msgid "No notifications yet!" -msgstr "" +msgstr "Noch keine Mitteilungen!" #: src/view/com/composer/text-input/mobile/Autocomplete.tsx:97 #: src/view/com/composer/text-input/web/Autocomplete.tsx:191 msgid "No result" msgstr "Kein Ergebnis" +#: src/components/Lists.tsx:192 +msgid "No results found" +msgstr "Keine Ergebnisse gefunden" + #: src/view/screens/Feeds.tsx:495 msgid "No results found for \"{query}\"" msgstr "Keine Ergebnisse für \"{query}\" gefunden" @@ -2573,7 +2443,7 @@ msgstr "Keine Ergebnisse für {query} gefunden" #: src/view/com/modals/EmbedConsent.tsx:129 msgid "No thanks" -msgstr "" +msgstr "Nein danke" #: src/view/com/modals/Threadgate.tsx:82 msgid "Nobody" @@ -2583,21 +2453,21 @@ msgstr "Niemand" msgid "Not Applicable." msgstr "Unzutreffend." -#: src/Navigation.tsx:105 +#: src/Navigation.tsx:107 #: src/view/screens/Profile.tsx:106 msgid "Not Found" -msgstr "" +msgstr "Nicht gefunden" #: src/view/com/modals/VerifyEmail.tsx:246 #: src/view/com/modals/VerifyEmail.tsx:252 msgid "Not right now" -msgstr "" +msgstr "Im Moment nicht" #: src/view/screens/Moderation.tsx:252 msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites." msgstr "Hinweis: Bluesky ist ein offenes und öffentliches Netzwerk. Diese Einstellung schränkt lediglich die Sichtbarkeit deiner Inhalte in der Bluesky-App und auf der Website ein. Andere Apps respektieren diese Einstellung möglicherweise nicht. Deine Inhalte werden abgemeldeten Nutzern möglicherweise weiterhin in anderen Apps und Websites angezeigt." -#: src/Navigation.tsx:450 +#: src/Navigation.tsx:457 #: src/view/screens/Notifications.tsx:124 #: src/view/screens/Notifications.tsx:148 #: src/view/shell/bottom-bar/BottomBar.tsx:205 @@ -2609,7 +2479,7 @@ msgstr "Mitteilungen" #: src/view/com/modals/SelfLabel.tsx:103 msgid "Nudity" -msgstr "" +msgstr "Nacktheit" #: src/view/com/util/ErrorBoundary.tsx:35 msgid "Oh no!" @@ -2617,7 +2487,7 @@ msgstr "Oh nein!" #: src/screens/Onboarding/StepInterests/index.tsx:128 msgid "Oh no! Something went wrong." -msgstr "" +msgstr "Oh nein, da ist etwas schief gelaufen." #: src/view/com/auth/login/PasswordUpdatedForm.tsx:41 msgid "Okay" @@ -2625,11 +2495,11 @@ msgstr "Okay" #: src/view/screens/PreferencesThreads.tsx:78 msgid "Oldest replies first" -msgstr "" +msgstr "Älteste Antworten zuerst" #: src/view/screens/Settings/index.tsx:234 msgid "Onboarding reset" -msgstr "" +msgstr "Onboarding zurücksetzen" #: src/view/com/composer/Composer.tsx:382 msgid "One or more images is missing alt text." @@ -2639,59 +2509,68 @@ msgstr "Bei einem oder mehreren Bildern fehlt der Alt-Text." msgid "Only {0} can reply." msgstr "Nur {0} kann antworten." +#: src/components/Lists.tsx:82 +msgid "Oops, something went wrong!" +msgstr "Ups, da ist etwas schief gelaufen!" + +#: src/components/Lists.tsx:188 #: src/view/screens/AppPasswords.tsx:65 #: src/view/screens/Profile.tsx:106 msgid "Oops!" -msgstr "" +msgstr "Huch!" #: src/screens/Onboarding/StepFinished.tsx:115 msgid "Open" -msgstr "" +msgstr "Öffnen" #: src/view/screens/Moderation.tsx:75 msgid "Open content filtering settings" -msgstr "" +msgstr "Inhaltsfiltereinstellungen öffnen" #: src/view/com/composer/Composer.tsx:477 #: src/view/com/composer/Composer.tsx:478 msgid "Open emoji picker" -msgstr "" +msgstr "Emoji-Picker öffnen" #: src/view/screens/Settings/index.tsx:712 msgid "Open links with in-app browser" -msgstr "" +msgstr "Links mit In-App-Browser öffnen" #: src/view/screens/Moderation.tsx:92 msgid "Open muted words settings" -msgstr "" +msgstr "Einstellungen für stummgeschaltete Wörter öffnen" -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:49 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:50 msgid "Open navigation" msgstr "Navigation öffnen" +#: src/view/com/util/forms/PostDropdownBtn.tsx:175 +msgid "Open post options menu" +msgstr "Beitragsoptionsmenü öffnen" + #: src/view/screens/Settings/index.tsx:804 msgid "Open storybook page" -msgstr "" +msgstr "Geschichtenbuch öffnen" #: src/view/com/util/forms/DropdownButton.tsx:154 msgid "Opens {numItems} options" -msgstr "" +msgstr "Öffnet {numItems} Optionen" #: src/view/screens/Log.tsx:54 msgid "Opens additional details for a debug entry" -msgstr "" +msgstr "Öffnet zusätzliche Details für einen Debug-Eintrag" -#: src/view/com/notifications/FeedItem.tsx:348 +#: src/view/com/notifications/FeedItem.tsx:349 msgid "Opens an expanded list of users in this notification" -msgstr "" +msgstr "Öffnet eine erweiterte Liste der Benutzer in dieser Meldung" #: src/view/com/composer/photos/OpenCameraBtn.tsx:61 msgid "Opens camera on device" -msgstr "" +msgstr "Öffnet die Kamera auf dem Gerät" #: src/view/com/composer/Prompt.tsx:25 msgid "Opens composer" -msgstr "" +msgstr "Öffnet den Beitragsverfasser" #: src/view/screens/Settings/index.tsx:595 msgid "Opens configurable language settings" @@ -2699,27 +2578,23 @@ msgstr "Öffnet die konfigurierbaren Spracheinstellungen" #: src/view/com/composer/photos/SelectPhotoBtn.tsx:44 msgid "Opens device photo gallery" -msgstr "" +msgstr "Öffnet die Gerätefotogalerie" #: src/view/com/profile/ProfileHeader.tsx:420 msgid "Opens editor for profile display name, avatar, background image, and description" -msgstr "" +msgstr "Öffnet den Editor für Profilanzeige, Avatar, Hintergrundbild und Beschreibung" #: src/view/screens/Settings/index.tsx:649 msgid "Opens external embeds settings" -msgstr "" +msgstr "Öffnet die Einstellungen für externe eingebettete Medien" #: src/view/com/profile/ProfileHeader.tsx:575 msgid "Opens followers list" -msgstr "" +msgstr "Öffnet die Follower-Liste" #: src/view/com/profile/ProfileHeader.tsx:594 msgid "Opens following list" -msgstr "" - -#: src/view/screens/Settings.tsx:412 -#~ msgid "Opens invite code list" -#~ msgstr "" +msgstr "Öffnet folgende Liste" #: src/view/com/modals/InviteCodes.tsx:172 msgid "Opens list of invite codes" @@ -2727,7 +2602,7 @@ msgstr "Öffnet die Liste der Einladungscodes" #: src/view/screens/Settings/index.tsx:774 msgid "Opens modal for account deletion confirmation. Requires email code." -msgstr "" +msgstr "Öffnet ein Modal, um die Löschung des Kontos zu bestätigen. Erfordert einen E-Mail-Code." #: src/view/com/modals/ChangeHandle.tsx:281 msgid "Opens modal for using custom domain" @@ -2739,12 +2614,12 @@ msgstr "Öffnet die Moderationseinstellungen" #: src/view/com/auth/login/LoginForm.tsx:239 msgid "Opens password reset form" -msgstr "" +msgstr "Öffnet das Formular zum Zurücksetzen des Passworts" -#: src/view/com/home/HomeHeaderLayout.web.tsx:60 +#: src/view/com/home/HomeHeaderLayout.web.tsx:63 #: src/view/screens/Feeds.tsx:356 msgid "Opens screen to edit Saved Feeds" -msgstr "" +msgstr "Öffnet den Bildschirm zum Bearbeiten gespeicherten Feeds" #: src/view/screens/Settings/index.tsx:576 msgid "Opens screen with all saved feeds" @@ -2760,7 +2635,7 @@ msgstr "Öffnet die Home-Feed-Einstellungen" #: src/view/screens/Settings/index.tsx:805 msgid "Opens the storybook page" -msgstr "" +msgstr "Öffnet die Geschichtenbuch" #: src/view/screens/Settings/index.tsx:793 msgid "Opens the system log page" @@ -2772,34 +2647,31 @@ msgstr "Öffnet die Thread-Einstellungen" #: src/view/com/util/forms/DropdownButton.tsx:280 msgid "Option {0} of {numItems}" -msgstr "" +msgstr "Option {0} von {numItems}" #: src/view/com/modals/Threadgate.tsx:89 msgid "Or combine these options:" -msgstr "" +msgstr "Oder kombiniere diese Optionen:" #: src/view/com/auth/login/ChooseAccountForm.tsx:138 msgid "Other account" msgstr "Anderes Konto" -#: src/view/com/modals/ServerInput.tsx:88 -#~ msgid "Other service" -#~ msgstr "Anderer Service" - #: src/view/com/composer/select-language/SelectLangBtn.tsx:91 msgid "Other..." msgstr "Andere..." +#: src/components/Lists.tsx:194 #: src/view/screens/NotFound.tsx:45 msgid "Page not found" msgstr "Seite nicht gefunden" #: src/view/screens/NotFound.tsx:42 msgid "Page Not Found" -msgstr "" +msgstr "Seite nicht gefunden" -#: src/view/com/auth/create/Step1.tsx:214 -#: src/view/com/auth/create/Step1.tsx:224 +#: src/view/com/auth/create/Step1.tsx:191 +#: src/view/com/auth/create/Step1.tsx:201 #: src/view/com/auth/login/LoginForm.tsx:226 #: src/view/com/auth/login/SetNewPasswordForm.tsx:161 #: src/view/com/modals/DeleteAccount.tsx:202 @@ -2814,29 +2686,25 @@ msgstr "Passwort aktualisiert" msgid "Password updated!" msgstr "Passwort aktualisiert!" -#: src/Navigation.tsx:160 +#: src/Navigation.tsx:162 msgid "People followed by @{0}" -msgstr "" +msgstr "Personen gefolgt von @{0}" -#: src/Navigation.tsx:153 +#: src/Navigation.tsx:155 msgid "People following @{0}" -msgstr "" +msgstr "Personen, die @{0} folgen" #: src/view/com/lightbox/Lightbox.tsx:66 msgid "Permission to access camera roll is required." -msgstr "" +msgstr "Die Erlaubnis zum Zugriff auf die Kamerarolle ist erforderlich." #: src/view/com/lightbox/Lightbox.tsx:72 msgid "Permission to access camera roll was denied. Please enable it in your system settings." -msgstr "" +msgstr "Die Berechtigung zum Zugriff auf die Kamerarolle wurde verweigert. Bitte aktiviere sie in deinen Systemeinstellungen." #: src/screens/Onboarding/index.tsx:31 msgid "Pets" -msgstr "" - -#: src/view/com/auth/create/Step2.tsx:183 -#~ msgid "Phone number" -#~ msgstr "" +msgstr "Haustiere" #: src/view/com/modals/SelfLabel.tsx:121 msgid "Pictures meant for adults." @@ -2845,7 +2713,7 @@ msgstr "Bilder, die für Erwachsene bestimmt sind." #: src/view/screens/ProfileFeed.tsx:354 #: src/view/screens/ProfileList.tsx:581 msgid "Pin to home" -msgstr "" +msgstr "An die Startseite anheften" #: src/view/screens/SavedFeeds.tsx:88 msgid "Pinned Feeds" @@ -2853,16 +2721,16 @@ msgstr "Angeheftete Feeds" #: src/view/com/util/post-embeds/ExternalGifEmbed.tsx:111 msgid "Play {0}" -msgstr "" +msgstr "{0} abspielen" #: src/view/com/util/post-embeds/ExternalPlayerEmbed.tsx:54 #: src/view/com/util/post-embeds/ExternalPlayerEmbed.tsx:55 msgid "Play Video" -msgstr "" +msgstr "Video abspielen" #: src/view/com/util/post-embeds/ExternalGifEmbed.tsx:110 msgid "Plays the GIF" -msgstr "" +msgstr "Spielt das GIF ab" #: src/view/com/auth/create/state.ts:124 msgid "Please choose your handle." @@ -2874,7 +2742,7 @@ msgstr "Bitte wähle dein Passwort." #: src/view/com/auth/create/state.ts:131 msgid "Please complete the verification captcha." -msgstr "" +msgstr "Bitte fülle das Verifizierungs-Captcha aus." #: src/view/com/modals/ChangeEmail.tsx:67 msgid "Please confirm your email before changing it. This is a temporary requirement while email-updating tools are added, and it will soon be removed." @@ -2882,23 +2750,15 @@ msgstr "Bitte bestätige deine E-Mail, bevor du sie änderst. Dies ist eine vorà #: src/view/com/modals/AddAppPasswords.tsx:90 msgid "Please enter a name for your app password. All spaces is not allowed." -msgstr "" - -#: src/view/com/auth/create/Step2.tsx:206 -#~ msgid "Please enter a phone number that can receive SMS text messages." -#~ msgstr "" +msgstr "Bitte gib einen Namen für dein App-Passwort ein. Nur Leerzeichen sind nicht erlaubt." #: src/view/com/modals/AddAppPasswords.tsx:145 msgid "Please enter a unique name for this App Password or use our randomly generated one." -msgstr "" - -#: src/view/com/auth/create/state.ts:170 -#~ msgid "Please enter the code you received by SMS." -#~ msgstr "" +msgstr "Bitte gib einen eindeutigen Namen für dieses App-Passwort ein oder verwende unseren zufällig generierten Namen." -#: src/view/com/auth/create/Step2.tsx:282 -#~ msgid "Please enter the verification code sent to {phoneNumberFormatted}." -#~ msgstr "" +#: src/components/dialogs/MutedWords.tsx:68 +msgid "Please enter a valid word, tag, or phrase to mute" +msgstr "Bitte gib ein gültiges Wort, einen Tag oder eine Phrase zum Stummschalten ein" #: src/view/com/auth/create/state.ts:103 msgid "Please enter your email." @@ -2915,25 +2775,25 @@ msgstr "Bitte teile uns mit, warum du denkst, dass diese Inhaltswarnung falsch a #: src/view/com/modals/VerifyEmail.tsx:101 msgid "Please Verify Your Email" -msgstr "" +msgstr "Bitte verifiziere deine E-Mail" #: src/view/com/composer/Composer.tsx:222 msgid "Please wait for your link card to finish loading" -msgstr "" +msgstr "Bitte warte, bis deine Link-karte vollständig geladen ist" #: src/screens/Onboarding/index.tsx:37 msgid "Politics" -msgstr "" +msgstr "Politik" #: src/view/com/modals/SelfLabel.tsx:111 msgid "Porn" -msgstr "" +msgstr "Porno" #: src/view/com/composer/Composer.tsx:357 #: src/view/com/composer/Composer.tsx:365 msgctxt "action" msgid "Post" -msgstr "" +msgstr "Beitrag" #: src/view/com/post-thread/PostThread.tsx:303 msgctxt "description" @@ -2942,17 +2802,17 @@ msgstr "Beitrag" #: src/view/com/post-thread/PostThreadItem.tsx:175 msgid "Post by {0}" -msgstr "" +msgstr "Beitrag von {0}" -#: src/Navigation.tsx:172 -#: src/Navigation.tsx:179 -#: src/Navigation.tsx:186 +#: src/Navigation.tsx:174 +#: src/Navigation.tsx:181 +#: src/Navigation.tsx:188 msgid "Post by @{0}" -msgstr "" +msgstr "Beitrag von @{0}" -#: src/view/com/util/forms/PostDropdownBtn.tsx:90 +#: src/view/com/util/forms/PostDropdownBtn.tsx:108 msgid "Post deleted" -msgstr "" +msgstr "Beitrag gelöscht" #: src/view/com/post-thread/PostThread.tsx:462 msgid "Post hidden" @@ -2970,21 +2830,21 @@ msgstr "Beitragssprachen" msgid "Post not found" msgstr "Beitrag nicht gefunden" -#: src/components/TagMenu/index.tsx:257 +#: src/components/TagMenu/index.tsx:253 msgid "posts" -msgstr "" +msgstr "Beiträge" #: src/view/screens/Profile.tsx:180 msgid "Posts" msgstr "Beiträge" -#: src/components/dialogs/MutedWords.tsx:77 +#: src/components/dialogs/MutedWords.tsx:90 msgid "Posts can be muted based on their text, their tags, or both." -msgstr "" +msgstr "Beiträge können basierend auf ihrem Text, ihren Tags oder beidem stummgeschaltet werden." #: src/view/com/posts/FeedErrorMessage.tsx:64 msgid "Posts hidden" -msgstr "" +msgstr "Ausgeblendete Beiträge" #: src/view/com/modals/LinkWarning.tsx:46 msgid "Potentially Misleading Link" @@ -3007,7 +2867,7 @@ msgstr "Priorisiere deine Follower" msgid "Privacy" msgstr "Privatsphäre" -#: src/Navigation.tsx:217 +#: src/Navigation.tsx:219 #: src/view/screens/PrivacyPolicy.tsx:29 #: src/view/screens/Settings/index.tsx:891 #: src/view/shell/Drawer.tsx:262 @@ -3028,7 +2888,7 @@ msgstr "Profil" #: src/view/com/modals/EditProfile.tsx:128 msgid "Profile updated" -msgstr "" +msgstr "Profil aktualisiert" #: src/view/screens/Settings/index.tsx:949 msgid "Protect your account by verifying your email." @@ -3036,7 +2896,7 @@ msgstr "Schütze dein Konto, indem du deine E-Mail bestätigst." #: src/screens/Onboarding/StepFinished.tsx:101 msgid "Public" -msgstr "" +msgstr "Öffentlich" #: src/view/screens/ModerationModlists.tsx:61 msgid "Public, shareable lists of users to mute or block in bulk." @@ -3048,11 +2908,11 @@ msgstr "Öffentliche, gemeinsam nutzbare Listen, die Feeds steuern können." #: src/view/com/composer/Composer.tsx:342 msgid "Publish post" -msgstr "" +msgstr "Beitrag veröffentlichen" #: src/view/com/composer/Composer.tsx:342 msgid "Publish reply" -msgstr "" +msgstr "Antwort veröffentlichen" #: src/view/com/modals/Repost.tsx:65 msgctxt "action" @@ -3070,11 +2930,11 @@ msgstr "Beitrag zitieren" #: src/view/screens/PreferencesThreads.tsx:86 msgid "Random (aka \"Poster's Roulette\")" -msgstr "" +msgstr "Zufällig (alias \"Poster's Roulette\")" #: src/view/com/modals/EditImage.tsx:236 msgid "Ratios" -msgstr "" +msgstr "Verhältnisse" #: src/view/com/auth/onboarding/RecommendedFeeds.tsx:116 msgid "Recommended Feeds" @@ -3084,7 +2944,7 @@ msgstr "Empfohlene Feeds" msgid "Recommended Users" msgstr "Empfohlene Nutzer" -#: src/components/dialogs/MutedWords.tsx:249 +#: src/components/dialogs/MutedWords.tsx:298 #: src/view/com/modals/ListAddRemoveUsers.tsx:264 #: src/view/com/modals/SelfLabel.tsx:83 #: src/view/com/modals/UserAddRemoveLists.tsx:219 @@ -3122,13 +2982,13 @@ msgstr "Bild entfernen" msgid "Remove image preview" msgstr "Bildvorschau entfernen" -#: src/components/dialogs/MutedWords.tsx:294 +#: src/components/dialogs/MutedWords.tsx:343 msgid "Remove mute word from your list" -msgstr "" +msgstr "Stummgeschaltetes Wort aus deiner Liste entfernen" #: src/view/com/modals/Repost.tsx:47 msgid "Remove repost" -msgstr "" +msgstr "Repost entfernen" #: src/view/com/feeds/FeedSourceCard.tsx:175 msgid "Remove this feed from my feeds?" @@ -3146,11 +3006,11 @@ msgstr "Aus der Liste entfernt" #: src/view/com/feeds/FeedSourceCard.tsx:113 #: src/view/com/feeds/FeedSourceCard.tsx:180 msgid "Removed from my feeds" -msgstr "" +msgstr "Aus meinen Feeds entfernt" #: src/view/com/composer/ExternalEmbed.tsx:71 msgid "Removes default thumbnail from {0}" -msgstr "" +msgstr "Entfernt Standard-Miniaturansicht von {0}" #: src/view/screens/Profile.tsx:181 msgid "Replies" @@ -3163,7 +3023,7 @@ msgstr "Antworten auf diesen Thread sind deaktiviert" #: src/view/com/composer/Composer.tsx:355 msgctxt "action" msgid "Reply" -msgstr "" +msgstr "Antworten" #: src/view/screens/PreferencesFollowingFeed.tsx:144 msgid "Reply Filters" @@ -3173,7 +3033,7 @@ msgstr "Antwortfilter" #: src/view/com/posts/FeedItem.tsx:287 msgctxt "description" msgid "Reply to <0/>" -msgstr "" +msgstr "Antwort an <0/>" #: src/view/com/modals/report/Modal.tsx:166 msgid "Report {collectionName}" @@ -3192,7 +3052,8 @@ msgid "Report List" msgstr "Liste melden" #: src/view/com/modals/report/SendReportButton.tsx:37 -#: src/view/com/util/forms/PostDropdownBtn.tsx:255 +#: src/view/com/util/forms/PostDropdownBtn.tsx:301 +#: src/view/com/util/forms/PostDropdownBtn.tsx:309 msgid "Report post" msgstr "Beitrag melden" @@ -3202,7 +3063,7 @@ msgstr "Beitrag melden" #: src/view/com/util/post-ctrls/RepostButton.tsx:61 msgctxt "action" msgid "Repost" -msgstr "" +msgstr "Repost" #: src/view/com/util/post-ctrls/RepostButton.web.tsx:48 msgid "Repost" @@ -3211,47 +3072,43 @@ msgstr "Erneut veröffentlichen" #: src/view/com/util/post-ctrls/RepostButton.web.tsx:94 #: src/view/com/util/post-ctrls/RepostButton.web.tsx:105 msgid "Repost or quote post" -msgstr "" +msgstr "Reposten oder Beitrag zitieren" #: src/view/screens/PostRepostedBy.tsx:27 msgid "Reposted By" -msgstr "" +msgstr "Repostet von" #: src/view/com/posts/FeedItem.tsx:207 msgid "Reposted by {0}" -msgstr "" +msgstr "Repostet von {0}" #: src/view/com/posts/FeedItem.tsx:224 msgid "Reposted by <0/>" -msgstr "" +msgstr "Repostet von <0/>" #: src/view/com/notifications/FeedItem.tsx:162 msgid "reposted your post" -msgstr "" +msgstr "hat deinen Beitrag repostet" #: src/view/com/post-thread/PostThreadItem.tsx:188 msgid "Reposts of this post" -msgstr "" +msgstr "Reposts von diesem Beitrag" #: src/view/com/modals/ChangeEmail.tsx:181 #: src/view/com/modals/ChangeEmail.tsx:183 msgid "Request Change" msgstr "Änderung anfordern" -#: src/view/com/auth/create/Step2.tsx:219 -#~ msgid "Request code" -#~ msgstr "" - #: src/view/com/modals/ChangePassword.tsx:239 #: src/view/com/modals/ChangePassword.tsx:241 msgid "Request Code" -msgstr "" +msgstr "Einen Code anfordern" #: src/view/screens/Settings/index.tsx:456 msgid "Require alt text before posting" -msgstr "" +msgstr "Alt-Text vor der Veröffentlichung erforderlich machen" -#: src/view/com/auth/create/Step1.tsx:153 +#: src/view/com/auth/create/Step1.tsx:146 msgid "Required for this provider" msgstr "Für diesen Anbieter erforderlich" @@ -3262,15 +3119,15 @@ msgstr "Code zurücksetzen" #: src/view/com/modals/ChangePassword.tsx:190 msgid "Reset Code" -msgstr "" +msgstr "Code zurücksetzen" #: src/view/screens/Settings/index.tsx:824 msgid "Reset onboarding" -msgstr "" +msgstr "Onboarding zurücksetzen" #: src/view/screens/Settings/index.tsx:827 msgid "Reset onboarding state" -msgstr "" +msgstr "Onboarding-Status zurücksetzen" #: src/view/com/auth/login/ForgotPasswordForm.tsx:104 msgid "Reset password" @@ -3278,28 +3135,28 @@ msgstr "Passwort zurücksetzen" #: src/view/screens/Settings/index.tsx:814 msgid "Reset preferences" -msgstr "" +msgstr "Einstellungen zurücksetzen" #: src/view/screens/Settings/index.tsx:817 msgid "Reset preferences state" -msgstr "" +msgstr "Einstellungen zurücksetzen" #: src/view/screens/Settings/index.tsx:825 msgid "Resets the onboarding state" -msgstr "" +msgstr "Setzt den Onboarding-Status zurück" #: src/view/screens/Settings/index.tsx:815 msgid "Resets the preferences state" -msgstr "" +msgstr "Einstellungen zurücksetzen" #: src/view/com/auth/login/LoginForm.tsx:269 msgid "Retries login" -msgstr "" +msgstr "Versucht die Anmeldung erneut" #: src/view/com/util/error/ErrorMessage.tsx:57 #: src/view/com/util/error/ErrorScreen.tsx:74 msgid "Retries the last action, which errored out" -msgstr "" +msgstr "Wiederholung der letzten Aktion, bei der ein Fehler aufgetreten ist" #: src/screens/Onboarding/StepInterests/index.tsx:221 #: src/screens/Onboarding/StepInterests/index.tsx:224 @@ -3312,23 +3169,15 @@ msgstr "" msgid "Retry" msgstr "Wiederholen" -#: src/view/com/auth/create/Step2.tsx:247 -#~ msgid "Retry." -#~ msgstr "" - -#: src/view/screens/ProfileList.tsx:898 +#: src/view/screens/ProfileList.tsx:903 msgid "Return to previous page" -msgstr "" - -#: src/view/shell/desktop/RightNav.tsx:55 -#~ msgid "SANDBOX. Posts and accounts are not permanent." -#~ msgstr "" +msgstr "Zurück zur vorherigen Seite" #: src/view/com/lightbox/Lightbox.tsx:132 #: src/view/com/modals/CreateOrEditList.tsx:345 msgctxt "action" msgid "Save" -msgstr "" +msgstr "Speichern" #: src/view/com/modals/BirthDateSettings.tsx:94 #: src/view/com/modals/BirthDateSettings.tsx:97 @@ -3361,21 +3210,21 @@ msgstr "Gespeicherte Feeds" #: src/view/com/modals/EditProfile.tsx:225 msgid "Saves any changes to your profile" -msgstr "" +msgstr "Speichert alle Änderungen an Deinem Profil" #: src/view/com/modals/ChangeHandle.tsx:171 msgid "Saves handle change to {handle}" -msgstr "" +msgstr "Speichert Handle-Änderung in {handle}" #: src/screens/Onboarding/index.tsx:36 msgid "Science" -msgstr "" +msgstr "Wissenschaft" -#: src/view/screens/ProfileList.tsx:854 +#: src/view/screens/ProfileList.tsx:859 msgid "Scroll to top" -msgstr "" +msgstr "Zum Anfang blättern" -#: src/Navigation.tsx:440 +#: src/Navigation.tsx:447 #: src/view/com/auth/LoggedOut.tsx:122 #: src/view/com/modals/ListAddRemoveUsers.tsx:75 #: src/view/com/util/forms/SearchInput.tsx:67 @@ -3395,15 +3244,15 @@ msgstr "Suche" #: src/view/screens/Search/Search.tsx:735 #: src/view/shell/desktop/Search.tsx:255 msgid "Search for \"{query}\"" -msgstr "" +msgstr "Suche nach \"{query}\"" #: src/components/TagMenu/index.tsx:145 -msgid "Search for all posts by @{authorHandle} with tag {tag}" -msgstr "" +msgid "Search for all posts by @{authorHandle} with tag {displayTag}" +msgstr "Nach allen Beiträgen von @{authorHandle} mit dem Tag {displayTag} suchen" -#: src/components/TagMenu/index.tsx:90 -msgid "Search for all posts with tag {tag}" -msgstr "" +#: src/components/TagMenu/index.tsx:94 +msgid "Search for all posts with tag {displayTag}" +msgstr "Nach allen Beiträgen mit dem Tag {displayTag} suchen" #: src/view/com/auth/LoggedOut.tsx:104 #: src/view/com/auth/LoggedOut.tsx:105 @@ -3415,25 +3264,25 @@ msgstr "Nach Nutzern suchen" msgid "Security Step Required" msgstr "Sicherheitsschritt erforderlich" -#: src/components/TagMenu/index.web.tsx:50 +#: src/components/TagMenu/index.web.tsx:66 msgid "See {truncatedTag} posts" -msgstr "" +msgstr "Siehe {truncatedTag}-Beiträge" -#: src/components/TagMenu/index.web.tsx:67 +#: src/components/TagMenu/index.web.tsx:83 msgid "See {truncatedTag} posts by user" -msgstr "" +msgstr "Siehe {truncatedTag}-Beiträge des Benutzers" #: src/components/TagMenu/index.tsx:128 -msgid "See <0>{tag}</0> posts" -msgstr "" +msgid "See <0>{displayTag}</0> posts" +msgstr "Siehe <0>{displayTag}</0>-Beiträge" -#: src/components/TagMenu/index.tsx:189 -msgid "See <0>{tag}</0> posts by this user" -msgstr "" +#: src/components/TagMenu/index.tsx:187 +msgid "See <0>{displayTag}</0> posts by this user" +msgstr "Siehe <0>{displayTag}</0>-Beiträge von diesem Benutzer" #: src/view/screens/SavedFeeds.tsx:163 msgid "See this guide" -msgstr "" +msgstr "Siehe diesen Leitfaden" #: src/view/com/auth/HomeLoggedOutCTA.tsx:39 msgid "See what's next" @@ -3441,11 +3290,7 @@ msgstr "Schau, was als nächstes kommt" #: src/view/com/util/Selector.tsx:106 msgid "Select {item}" -msgstr "" - -#: src/view/com/modals/ServerInput.tsx:75 -#~ msgid "Select Bluesky Social" -#~ msgstr "Wähle Bluesky Social" +msgstr "Wähle {item}" #: src/view/com/auth/login/Login.tsx:117 msgid "Select from an existing account" @@ -3453,32 +3298,28 @@ msgstr "Von einem bestehenden Konto auswählen" #: src/view/com/util/Selector.tsx:107 msgid "Select option {i} of {numItems}" -msgstr "" +msgstr "Wähle Option {i} von {numItems}" -#: src/view/com/auth/create/Step1.tsx:103 +#: src/view/com/auth/create/Step1.tsx:96 #: src/view/com/auth/login/LoginForm.tsx:150 msgid "Select service" msgstr "Service auswählen" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:52 msgid "Select some accounts below to follow" -msgstr "" +msgstr "Wähle unten einige Konten aus, denen du folgen möchtest" #: src/view/com/auth/server-input/index.tsx:82 msgid "Select the service that hosts your data." -msgstr "" - -#: src/screens/Onboarding/StepModeration/index.tsx:49 -#~ msgid "Select the types of content that you want to see (or not see), and we'll handle the rest." -#~ msgstr "" +msgstr "Wähle den Dienst aus, der deine Daten hostet." #: src/screens/Onboarding/StepTopicalFeeds.tsx:96 msgid "Select topical feeds to follow from the list below" -msgstr "" +msgstr "Wähle aus der folgenden Liste die themenbezogenen Feeds aus, die du verfolgen möchtest" #: src/screens/Onboarding/StepModeration/index.tsx:75 msgid "Select what you want to see (or not see), and we’ll handle the rest." -msgstr "" +msgstr "Wähle aus, was du sehen (oder nicht sehen) möchtest, und wir kümmern uns um den Rest." #: src/view/screens/LanguageSettings.tsx:281 msgid "Select which languages you want your subscribed feeds to include. If none are selected, all languages will be shown." @@ -3490,11 +3331,7 @@ msgstr "Wählen deine App-Sprache für den Standardtext aus, der in der App ange #: src/screens/Onboarding/StepInterests/index.tsx:196 msgid "Select your interests from the options below" -msgstr "" - -#: src/view/com/auth/create/Step2.tsx:155 -#~ msgid "Select your phone's country" -#~ msgstr "" +msgstr "Wähle aus den folgenden Optionen deine Interessen aus" #: src/view/screens/LanguageSettings.tsx:190 msgid "Select your preferred language for translations in your feed." @@ -3502,11 +3339,11 @@ msgstr "Wähle deine bevorzugte Sprache für die Übersetzungen in deinem Feed a #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:116 msgid "Select your primary algorithmic feeds" -msgstr "" +msgstr "Wähle deine primären algorithmischen Feeds" #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:142 msgid "Select your secondary algorithmic feeds" -msgstr "" +msgstr "Wähle deine sekundären algorithmischen Feeds" #: src/view/com/modals/VerifyEmail.tsx:202 #: src/view/com/modals/VerifyEmail.tsx:204 @@ -3529,53 +3366,53 @@ msgstr "Feedback senden" #: src/view/com/modals/report/SendReportButton.tsx:45 msgid "Send Report" -msgstr "" +msgstr "Bericht senden" #: src/view/com/modals/DeleteAccount.tsx:133 msgid "Sends email with confirmation code for account deletion" -msgstr "" +msgstr "Sendet eine E-Mail mit Bestätigungscode für die Kontolöschung" #: src/view/com/auth/server-input/index.tsx:110 msgid "Server address" -msgstr "" +msgstr "Server-Adresse" #: src/view/com/modals/ContentFilteringSettings.tsx:311 msgid "Set {value} for {labelGroup} content moderation policy" -msgstr "" +msgstr "Legt {value} für die {labelGroup} Inhaltsmoderationsrichtlinie fest" #: src/view/com/modals/ContentFilteringSettings.tsx:160 #: src/view/com/modals/ContentFilteringSettings.tsx:179 msgctxt "action" msgid "Set Age" -msgstr "" +msgstr "Alter festlegen" #: src/view/screens/Settings/index.tsx:488 msgid "Set color theme to dark" -msgstr "" +msgstr "Farbthema auf dunkel einstellen" #: src/view/screens/Settings/index.tsx:481 msgid "Set color theme to light" -msgstr "" +msgstr "Farbthema auf hell einstellen" #: src/view/screens/Settings/index.tsx:475 msgid "Set color theme to system setting" -msgstr "" +msgstr "Farbthema auf Systemeinstellung setzen" #: src/view/screens/Settings/index.tsx:514 msgid "Set dark theme to the dark theme" -msgstr "" +msgstr "Dunkles Thema auf das dunkle Thema einstellen" #: src/view/screens/Settings/index.tsx:507 msgid "Set dark theme to the dim theme" -msgstr "" +msgstr "Dunkles Thema auf das gedämpfte Thema einstellen" #: src/view/com/auth/login/SetNewPasswordForm.tsx:104 msgid "Set new password" msgstr "Neues Passwort festlegen" -#: src/view/com/auth/create/Step1.tsx:225 +#: src/view/com/auth/create/Step1.tsx:202 msgid "Set password" -msgstr "" +msgstr "Passwort festlegen" #: src/view/screens/PreferencesFollowingFeed.tsx:225 msgid "Set this setting to \"No\" to hide all quote posts from your feed. Reposts will still be visible." @@ -3593,36 +3430,32 @@ msgstr "Setze diese Einstellung auf \"Nein\", um alle Reposts aus deinem Feed au msgid "Set this setting to \"Yes\" to show replies in a threaded view. This is an experimental feature." msgstr "Setze diese Einstellung auf \"Ja\", um Antworten in einer Thread-Ansicht anzuzeigen. Dies ist eine experimentelle Funktion." -#: src/view/screens/PreferencesHomeFeed.tsx:261 -#~ msgid "Set this setting to \"Yes\" to show samples of your saved feeds in your following feed. This is an experimental feature." -#~ msgstr "Setze diese Einstellung auf \"Ja\", um Beispiele für deine gespeicherten Feeds in deinem folgenden Feed anzuzeigen. Dies ist eine experimentelle Funktion." - #: src/view/screens/PreferencesFollowingFeed.tsx:261 msgid "Set this setting to \"Yes\" to show samples of your saved feeds in your Following feed. This is an experimental feature." -msgstr "" +msgstr "Setze diese Einstellung auf \"Ja\", um Beispiele für deine gespeicherten Feeds in deinem Following-Feed anzuzeigen. Dies ist eine experimentelle Funktion." #: src/screens/Onboarding/Layout.tsx:50 msgid "Set up your account" -msgstr "" +msgstr "Dein Konto einrichten" #: src/view/com/modals/ChangeHandle.tsx:266 msgid "Sets Bluesky username" -msgstr "" +msgstr "Legt deinen Bluesky-Benutzernamen fest" #: src/view/com/auth/login/ForgotPasswordForm.tsx:157 msgid "Sets email for password reset" -msgstr "" +msgstr "Legt die E-Mail für das Zurücksetzen des Passworts fest" #: src/view/com/auth/login/ForgotPasswordForm.tsx:122 msgid "Sets hosting provider for password reset" -msgstr "" +msgstr "Legt den Hosting-Anbieter für das Zurücksetzen des Passworts fest" -#: src/view/com/auth/create/Step1.tsx:104 +#: src/view/com/auth/create/Step1.tsx:97 #: src/view/com/auth/login/LoginForm.tsx:151 msgid "Sets server for the Bluesky client" -msgstr "" +msgstr "Setzt den Server für den Bluesky-Client" -#: src/Navigation.tsx:135 +#: src/Navigation.tsx:137 #: src/view/screens/Settings/index.tsx:294 #: src/view/shell/desktop/LeftNav.tsx:433 #: src/view/shell/Drawer.tsx:567 @@ -3637,10 +3470,12 @@ msgstr "Sexuelle Aktivitäten oder erotische Nacktheit." #: src/view/com/lightbox/Lightbox.tsx:141 msgctxt "action" msgid "Share" -msgstr "" +msgstr "Teilen" #: src/view/com/profile/ProfileHeader.tsx:295 -#: src/view/com/util/forms/PostDropdownBtn.tsx:184 +#: src/view/com/util/forms/PostDropdownBtn.tsx:231 +#: src/view/com/util/forms/PostDropdownBtn.tsx:237 +#: src/view/com/util/post-ctrls/PostCtrls.tsx:215 #: src/view/screens/ProfileList.tsx:418 msgid "Share" msgstr "Teilen" @@ -3659,7 +3494,7 @@ msgstr "Anzeigen" #: src/view/screens/PreferencesFollowingFeed.tsx:68 msgid "Show all replies" -msgstr "" +msgstr "Alle Antworten anzeigen" #: src/view/com/util/moderation/ScreenHider.tsx:132 msgid "Show anyway" @@ -3667,17 +3502,17 @@ msgstr "Trotzdem anzeigen" #: src/view/com/modals/EmbedConsent.tsx:87 msgid "Show embeds from {0}" -msgstr "" +msgstr "Eingebettete Medien von {0} anzeigen" #: src/view/com/profile/ProfileHeader.tsx:459 msgid "Show follows similar to {0}" -msgstr "" +msgstr "Zeige ähnliche Konten wie {0}" #: src/view/com/post-thread/PostThreadItem.tsx:538 #: src/view/com/post/Post.tsx:198 #: src/view/com/posts/FeedItem.tsx:363 msgid "Show More" -msgstr "" +msgstr "Mehr anzeigen" #: src/view/screens/PreferencesFollowingFeed.tsx:258 msgid "Show Posts from My Feeds" @@ -3685,19 +3520,19 @@ msgstr "Beiträge aus meinen Feeds anzeigen" #: src/view/screens/PreferencesFollowingFeed.tsx:222 msgid "Show Quote Posts" -msgstr "" +msgstr "Zitierte Beiträge anzeigen" #: src/screens/Onboarding/StepFollowingFeed.tsx:118 msgid "Show quote-posts in Following feed" -msgstr "" +msgstr "Zitierte Beiträge im Following Feed anzeigen" #: src/screens/Onboarding/StepFollowingFeed.tsx:134 msgid "Show quotes in Following" -msgstr "" +msgstr "Zitierte Beiträge im Following Feed anzeigen" #: src/screens/Onboarding/StepFollowingFeed.tsx:94 msgid "Show re-posts in Following feed" -msgstr "" +msgstr "Reposts im Following-Feed anzeigen" #: src/view/screens/PreferencesFollowingFeed.tsx:119 msgid "Show Replies" @@ -3709,15 +3544,15 @@ msgstr "Zeige Antworten von Personen, denen du folgst, vor allen anderen Antwort #: src/screens/Onboarding/StepFollowingFeed.tsx:86 msgid "Show replies in Following" -msgstr "" +msgstr "Antworten in folgendem Feed anzeigen" #: src/screens/Onboarding/StepFollowingFeed.tsx:70 msgid "Show replies in Following feed" -msgstr "" +msgstr "Antworten in folgendem Feed anzeigen" #: src/view/screens/PreferencesFollowingFeed.tsx:70 msgid "Show replies with at least {value} {0}" -msgstr "" +msgstr "Antworten mit mindestens {value} {0} anzeigen" #: src/view/screens/PreferencesFollowingFeed.tsx:188 msgid "Show Reposts" @@ -3725,25 +3560,25 @@ msgstr "Reposts anzeigen" #: src/screens/Onboarding/StepFollowingFeed.tsx:110 msgid "Show reposts in Following" -msgstr "" +msgstr "Reposts im Following-Feed anzeigen" #: src/view/com/util/moderation/ContentHider.tsx:67 #: src/view/com/util/moderation/PostHider.tsx:61 msgid "Show the content" -msgstr "" +msgstr "Den Inhalt anzeigen" -#: src/view/com/notifications/FeedItem.tsx:346 +#: src/view/com/notifications/FeedItem.tsx:347 msgid "Show users" msgstr "Nutzer anzeigen" #: src/view/com/profile/ProfileHeader.tsx:462 msgid "Shows a list of users similar to this user." -msgstr "" +msgstr "Zeigt eine Liste von Benutzern, die diesem Benutzer ähnlich sind." #: src/view/com/post-thread/PostThreadFollowBtn.tsx:124 #: src/view/com/profile/ProfileHeader.tsx:506 msgid "Shows posts from {0} in your feed" -msgstr "" +msgstr "Zeigt Beiträge von {0} in deinem Feed" #: src/view/com/auth/HomeLoggedOutCTA.tsx:70 #: src/view/com/auth/login/Login.tsx:98 @@ -3811,11 +3646,11 @@ msgstr "Angemeldet als" #: src/view/com/auth/login/ChooseAccountForm.tsx:103 msgid "Signed in as @{0}" -msgstr "" +msgstr "Angemeldet als @{0}" #: src/view/com/modals/SwitchAccount.tsx:66 msgid "Signs {0} out of Bluesky" -msgstr "" +msgstr "Meldet {0} von Bluesky ab" #: src/screens/Onboarding/StepInterests/index.tsx:235 #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:195 @@ -3825,27 +3660,19 @@ msgstr "Überspringen" #: src/screens/Onboarding/StepInterests/index.tsx:232 msgid "Skip this flow" -msgstr "" - -#: src/view/com/auth/create/Step2.tsx:82 -#~ msgid "SMS verification" -#~ msgstr "" +msgstr "Diesen Schritt überspringen" #: src/screens/Onboarding/index.tsx:40 msgid "Software Dev" -msgstr "" +msgstr "Software-Entwicklung" -#: src/view/com/modals/ProfilePreview.tsx:62 -#~ msgid "Something went wrong and we're not sure what." -#~ msgstr "" +#: src/components/Lists.tsx:203 +msgid "Something went wrong!" +msgstr "Es ist ein Fehler aufgetreten." -#: src/view/com/modals/Waitlist.tsx:51 -msgid "Something went wrong. Check your email and try again." -msgstr "" - -#: src/App.native.tsx:63 +#: src/App.native.tsx:66 msgid "Sorry! Your session expired. Please log in again." -msgstr "" +msgstr "Entschuldigung! Deine Sitzung ist abgelaufen. Bitte logge dich erneut ein." #: src/view/screens/PreferencesThreads.tsx:69 msgid "Sort Replies" @@ -3857,15 +3684,11 @@ msgstr "Antworten auf denselben Beitrag sortieren nach:" #: src/screens/Onboarding/index.tsx:30 msgid "Sports" -msgstr "" +msgstr "Sport" #: src/view/com/modals/crop-image/CropImage.web.tsx:122 msgid "Square" -msgstr "" - -#: src/view/com/modals/ServerInput.tsx:62 -#~ msgid "Staging" -#~ msgstr "Staging" +msgstr "Quadratische" #: src/view/screens/Settings/index.tsx:871 msgid "Status page" @@ -3873,16 +3696,16 @@ msgstr "Status-Seite" #: src/view/com/auth/create/StepHeader.tsx:22 msgid "Step {0} of {numSteps}" -msgstr "" +msgstr "Schritt {0} von {numSteps}" #: src/view/screens/Settings/index.tsx:274 msgid "Storage cleared, you need to restart the app now." -msgstr "" +msgstr "Der Speicher wurde gelöscht, du musst die App jetzt neu starten." -#: src/Navigation.tsx:202 +#: src/Navigation.tsx:204 #: src/view/screens/Settings/index.tsx:807 msgid "Storybook" -msgstr "" +msgstr "Geschichtenbuch" #: src/view/com/modals/AppealLabel.tsx:101 msgid "Submit" @@ -3893,9 +3716,9 @@ msgid "Subscribe" msgstr "Abonnieren" #: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:173 -#: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:307 +#: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:308 msgid "Subscribe to the {0} feed" -msgstr "" +msgstr "Abonniere den {0} Feed" #: src/view/screens/ProfileList.tsx:604 msgid "Subscribe to this list" @@ -3907,22 +3730,18 @@ msgstr "Vorgeschlagene Follower" #: src/view/com/profile/ProfileHeaderSuggestedFollows.tsx:64 msgid "Suggested for you" -msgstr "" +msgstr "Vorgeschlagen für dich" #: src/view/com/modals/SelfLabel.tsx:95 msgid "Suggestive" -msgstr "" +msgstr "Suggestiv" -#: src/Navigation.tsx:212 +#: src/Navigation.tsx:214 #: src/view/screens/Support.tsx:30 #: src/view/screens/Support.tsx:33 msgid "Support" msgstr "Support" -#: src/view/com/modals/ProfilePreview.tsx:110 -#~ msgid "Swipe up to see more" -#~ msgstr "" - #: src/view/com/modals/SwitchAccount.tsx:117 msgid "Switch Account" msgstr "Konto wechseln" @@ -3930,28 +3749,28 @@ msgstr "Konto wechseln" #: src/view/com/modals/SwitchAccount.tsx:97 #: src/view/screens/Settings/index.tsx:130 msgid "Switch to {0}" -msgstr "" +msgstr "Wechseln zu {0}" #: src/view/com/modals/SwitchAccount.tsx:98 #: src/view/screens/Settings/index.tsx:131 msgid "Switches the account you are logged in to" -msgstr "" +msgstr "Wechselt das Konto, in das du eingeloggt bist" #: src/view/screens/Settings/index.tsx:472 msgid "System" -msgstr "" +msgstr "System" #: src/view/screens/Settings/index.tsx:795 msgid "System log" msgstr "Systemprotokoll" -#: src/components/dialogs/MutedWords.tsx:288 +#: src/components/dialogs/MutedWords.tsx:337 msgid "tag" -msgstr "" +msgstr "Tag" -#: src/components/TagMenu/index.tsx:74 -msgid "Tag menu: {tag}" -msgstr "" +#: src/components/TagMenu/index.tsx:78 +msgid "Tag menu: {displayTag}" +msgstr "Tag-Menü: {displayTag}" #: src/view/com/modals/crop-image/CropImage.web.tsx:112 msgid "Tall" @@ -3959,26 +3778,26 @@ msgstr "Groß" #: src/view/com/util/images/AutoSizedImage.tsx:70 msgid "Tap to view fully" -msgstr "" +msgstr "Tippe, um die vollständige Ansicht anzuzeigen" #: src/screens/Onboarding/index.tsx:39 msgid "Tech" -msgstr "" +msgstr "Technik" #: src/view/shell/desktop/RightNav.tsx:81 msgid "Terms" msgstr "Bedingungen" -#: src/Navigation.tsx:222 +#: src/Navigation.tsx:224 #: src/view/screens/Settings/index.tsx:885 #: src/view/screens/TermsOfService.tsx:29 #: src/view/shell/Drawer.tsx:256 msgid "Terms of Service" msgstr "Nutzungsbedingungen" -#: src/components/dialogs/MutedWords.tsx:288 +#: src/components/dialogs/MutedWords.tsx:337 msgid "text" -msgstr "" +msgstr "Text" #: src/view/com/modals/AppealLabel.tsx:70 #: src/view/com/modals/report/InputIssueDetails.tsx:51 @@ -3987,11 +3806,11 @@ msgstr "Text-Eingabefeld" #: src/view/com/auth/create/CreateAccount.tsx:94 msgid "That handle is already taken." -msgstr "" +msgstr "Dieser Handle ist bereits besetzt." #: src/view/com/profile/ProfileHeader.tsx:263 msgid "The account will be able to interact with you after unblocking." -msgstr "" +msgstr "Das Konto kann nach der Entblockiert mit dir interagieren." #: src/view/screens/CommunityGuidelines.tsx:36 msgid "The Community Guidelines have been moved to <0/>" @@ -3999,11 +3818,11 @@ msgstr "Die Community-Richtlinien wurden nach <0/> verschoben" #: src/view/screens/CopyrightPolicy.tsx:33 msgid "The Copyright Policy has been moved to <0/>" -msgstr "" +msgstr "Die Copyright-Richtlinie wurde nach <0/> verschoben" #: src/screens/Onboarding/Layout.tsx:60 msgid "The following steps will help customize your Bluesky experience." -msgstr "" +msgstr "Die folgenden Schritte helfen dir, dein Bluesky-Erlebnis anzupassen." #: src/view/com/post-thread/PostThread.tsx:517 msgid "The post may have been deleted." @@ -4019,23 +3838,23 @@ msgstr "Das Support-Formular wurde verschoben. Wenn du Hilfe benötigst, wende d #: src/view/screens/TermsOfService.tsx:33 msgid "The Terms of Service have been moved to" -msgstr "" +msgstr "Die Allgemeinen Geschäftsbedingungen wurden verschoben nach" #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:150 msgid "There are many feeds to try:" -msgstr "" +msgstr "Es gibt viele Feeds zum Ausprobieren:" #: src/view/screens/ProfileFeed.tsx:550 msgid "There was an an issue contacting the server, please check your internet connection and try again." -msgstr "" +msgstr "Es gab ein Problem bei der Kontaktaufnahme mit dem Server. Bitte überprüfe deine Internetverbindung und versuche es erneut." #: src/view/com/posts/FeedErrorMessage.tsx:139 msgid "There was an an issue removing this feed. Please check your internet connection and try again." -msgstr "" +msgstr "Es gab ein Problem beim Entfernen dieses Feeds. Bitte überprüfe deine Internetverbindung und versuche es erneut." #: src/view/screens/ProfileFeed.tsx:210 msgid "There was an an issue updating your feeds, please check your internet connection and try again." -msgstr "" +msgstr "Es gab ein Problem bei der Aktualisierung deines Feeds. Bitte überprüfe deine Internetverbindung und versuche es erneut." #: src/view/screens/ProfileFeed.tsx:237 #: src/view/screens/ProfileList.tsx:267 @@ -4043,7 +3862,7 @@ msgstr "" #: src/view/screens/SavedFeeds.tsx:231 #: src/view/screens/SavedFeeds.tsx:252 msgid "There was an issue contacting the server" -msgstr "" +msgstr "Es gab ein Problem bei der Kontaktaufnahme mit dem Server" #: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:57 #: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:66 @@ -4051,33 +3870,33 @@ msgstr "" #: src/view/com/feeds/FeedSourceCard.tsx:129 #: src/view/com/feeds/FeedSourceCard.tsx:183 msgid "There was an issue contacting your server" -msgstr "" +msgstr "Es gab ein Problem bei der Kontaktaufnahme mit deinem Server" #: src/view/com/notifications/Feed.tsx:117 msgid "There was an issue fetching notifications. Tap here to try again." -msgstr "" +msgstr "Es gab ein Problem beim Abrufen von Mitteilungen. Tippe hier, um es erneut zu versuchen." -#: src/view/com/posts/Feed.tsx:263 +#: src/view/com/posts/Feed.tsx:265 msgid "There was an issue fetching posts. Tap here to try again." -msgstr "" +msgstr "Es gab ein Problem beim Abrufen der Beiträge. Tippe hier, um es erneut zu versuchen." #: src/view/com/lists/ListMembers.tsx:172 msgid "There was an issue fetching the list. Tap here to try again." -msgstr "" +msgstr "Es gab ein Problem beim Abrufen der Liste. Tippe hier, um es erneut zu versuchen." #: src/view/com/feeds/ProfileFeedgens.tsx:148 #: src/view/com/lists/ProfileLists.tsx:155 msgid "There was an issue fetching your lists. Tap here to try again." -msgstr "" +msgstr "Es gab ein Problem beim Abrufen deiner Listen. Tippe hier, um es erneut zu versuchen." #: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:63 #: src/view/com/modals/ContentFilteringSettings.tsx:126 msgid "There was an issue syncing your preferences with the server" -msgstr "" +msgstr "Es gab ein Problem bei der Synchronisierung deiner Einstellungen mit dem Server" #: src/view/screens/AppPasswords.tsx:66 msgid "There was an issue with fetching your app passwords" -msgstr "" +msgstr "Es gab ein Problem beim Abrufen deiner App-Passwörter" #: src/view/com/post-thread/PostThreadFollowBtn.tsx:93 #: src/view/com/post-thread/PostThreadFollowBtn.tsx:105 @@ -4088,46 +3907,42 @@ msgstr "" #: src/view/com/profile/ProfileHeader.tsx:250 #: src/view/com/profile/ProfileHeader.tsx:272 msgid "There was an issue! {0}" -msgstr "" +msgstr "Es gab ein Problem! {0}" #: src/view/screens/ProfileList.tsx:288 #: src/view/screens/ProfileList.tsx:307 #: src/view/screens/ProfileList.tsx:329 #: src/view/screens/ProfileList.tsx:348 msgid "There was an issue. Please check your internet connection and try again." -msgstr "" +msgstr "Es ist ein Problem aufgetreten. Bitte überprüfe deine Internetverbindung und versuche es erneut." #: src/view/com/util/ErrorBoundary.tsx:36 msgid "There was an unexpected issue in the application. Please let us know if this happened to you!" -msgstr "" +msgstr "Es gab ein unerwartetes Problem in der Anwendung. Bitte teile uns mit, wenn dies bei dir der Fall ist!" #: src/screens/Deactivated.tsx:106 msgid "There's been a rush of new users to Bluesky! We'll activate your account as soon as we can." -msgstr "" - -#: src/view/com/auth/create/Step2.tsx:55 -#~ msgid "There's something wrong with this number. Please choose your country and enter your full phone number!" -#~ msgstr "" +msgstr "Es gab einen Ansturm neuer Nutzer auf Bluesky! Wir werden dein Konto so schnell wie möglich aktivieren." #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:138 msgid "These are popular accounts you might like:" -msgstr "" +msgstr "Dies sind beliebte Konten, die dir gefallen könnten:" #: src/view/com/util/moderation/ScreenHider.tsx:88 msgid "This {screenDescription} has been flagged:" -msgstr "" +msgstr "Diese {screenDescription} wurde gekennzeichnet:" #: src/view/com/util/moderation/ScreenHider.tsx:83 msgid "This account has requested that users sign in to view their profile." -msgstr "" +msgstr "Dieses Konto hat die Benutzer aufgefordert, sich anzumelden, um dein Profil zu sehen." #: src/view/com/modals/EmbedConsent.tsx:68 msgid "This content is hosted by {0}. Do you want to enable external media?" -msgstr "" +msgstr "Dieser Inhalt wird von {0} gehostet. Möchtest du externe Medien aktivieren?" #: src/view/com/modals/ModerationDetails.tsx:67 msgid "This content is not available because one of the users involved has blocked the other." -msgstr "" +msgstr "Dieser Inhalt ist nicht verfügbar, weil einer der beteiligten Nutzer den anderen blockiert hat." #: src/view/com/posts/FeedErrorMessage.tsx:108 msgid "This content is not viewable without a Bluesky account." @@ -4135,7 +3950,7 @@ msgstr "Dieser Inhalt ist ohne ein Bluesky-Konto nicht sichtbar." #: src/view/screens/Settings/ExportCarDialog.tsx:75 msgid "This feature is in beta. You can read more about repository exports in <0>this blogpost.</0>" -msgstr "" +msgstr "Diese Funktion befindet sich in der Beta-Phase. Du kannst mehr über Kontodepot-Exporte in <0>diesem Blogpost lesen.</0>" #: src/view/com/posts/FeedErrorMessage.tsx:114 msgid "This feed is currently receiving high traffic and is temporarily unavailable. Please try again later." @@ -4145,11 +3960,11 @@ msgstr "Dieser Feed wird derzeit stark frequentiert und ist vorübergehend nicht #: src/view/screens/ProfileFeed.tsx:476 #: src/view/screens/ProfileList.tsx:661 msgid "This feed is empty!" -msgstr "" +msgstr "Dieser Feed ist leer!" #: src/view/com/posts/CustomFeedEmptyState.tsx:37 msgid "This feed is empty! You may need to follow more users or tune your language settings." -msgstr "" +msgstr "Dieser Feed ist leer! Möglicherweise musst du mehr Benutzern folgen oder deine Spracheinstellungen anpassen." #: src/view/com/modals/BirthDateSettings.tsx:61 msgid "This information is not shared with other users." @@ -4163,13 +3978,13 @@ msgstr "Das ist wichtig für den Fall, dass du mal deine E-Mail ändern oder dei msgid "This link is taking you to the following website:" msgstr "Dieser Link führt dich auf die folgende Website:" -#: src/view/screens/ProfileList.tsx:834 +#: src/view/screens/ProfileList.tsx:839 msgid "This list is empty!" -msgstr "" +msgstr "Diese Liste ist leer!" #: src/view/com/modals/AddAppPasswords.tsx:106 msgid "This name is already in use" -msgstr "" +msgstr "Dieser Name ist bereits in Gebrauch" #: src/view/com/post-thread/PostThreadItem.tsx:125 msgid "This post has been deleted." @@ -4177,29 +3992,25 @@ msgstr "Dieser Beitrag wurde gelöscht." #: src/view/com/modals/ModerationDetails.tsx:62 msgid "This user has blocked you. You cannot view their content." -msgstr "" +msgstr "Dieser Benutzer hat dich blockiert. Du kannst deren Inhalte nicht sehen." #: src/view/com/modals/ModerationDetails.tsx:42 msgid "This user is included in the <0/> list which you have blocked." -msgstr "" +msgstr "Dieser Benutzer ist in der Liste <0/> enthalten, die du blockiert hast." #: src/view/com/modals/ModerationDetails.tsx:74 msgid "This user is included in the <0/> list which you have muted." -msgstr "" - -#: src/view/com/modals/ModerationDetails.tsx:74 -#~ msgid "This user is included the <0/> list which you have muted." -#~ msgstr "" +msgstr "Dieser Benutzer ist in der Liste <0/> enthalten, die du stummgeschaltet haben." #: src/view/com/modals/SelfLabel.tsx:137 msgid "This warning is only available for posts with media attached." msgstr "Diese Warnung ist nur für Beiträge mit angehängten Medien verfügbar." -#: src/components/dialogs/MutedWords.tsx:236 +#: src/components/dialogs/MutedWords.tsx:285 msgid "This will delete {0} from your muted words. You can always add it back later." -msgstr "" +msgstr "Dies wird {0} aus deinen stummgeschalteten Wörtern löschen. Du kannst es später jederzeit wieder hinzufügen." -#: src/view/com/util/forms/PostDropdownBtn.tsx:237 +#: src/view/com/util/forms/PostDropdownBtn.tsx:282 msgid "This will hide this post from your feeds." msgstr "Dadurch wird dieser Beitrag aus deinen Feeds ausgeblendet." @@ -4210,27 +4021,28 @@ msgstr "Thread-Einstellungen" #: src/view/screens/PreferencesThreads.tsx:119 msgid "Threaded Mode" -msgstr "" +msgstr "Gewindemodus" -#: src/Navigation.tsx:255 +#: src/Navigation.tsx:257 msgid "Threads Preferences" -msgstr "" +msgstr "Thread-Einstellungen" -#: src/components/dialogs/MutedWords.tsx:95 +#: src/components/dialogs/MutedWords.tsx:113 msgid "Toggle between muted word options." -msgstr "" +msgstr "Zwischen den Optionen für stummgeschaltete Wörter wechseln." #: src/view/com/util/forms/DropdownButton.tsx:246 msgid "Toggle dropdown" -msgstr "" +msgstr "Dieses Dropdown umschalten" #: src/view/com/modals/EditImage.tsx:271 msgid "Transformations" -msgstr "" +msgstr "Verwandlungen" #: src/view/com/post-thread/PostThreadItem.tsx:685 #: src/view/com/post-thread/PostThreadItem.tsx:687 -#: src/view/com/util/forms/PostDropdownBtn.tsx:156 +#: src/view/com/util/forms/PostDropdownBtn.tsx:215 +#: src/view/com/util/forms/PostDropdownBtn.tsx:217 msgid "Translate" msgstr "Übersetzen" @@ -4241,11 +4053,11 @@ msgstr "Erneut versuchen" #: src/view/screens/ProfileList.tsx:506 msgid "Un-block list" -msgstr "" +msgstr "Liste entblocken" #: src/view/screens/ProfileList.tsx:491 msgid "Un-mute list" -msgstr "" +msgstr "Stummschaltung von Liste aufheben" #: src/view/com/auth/create/CreateAccount.tsx:58 #: src/view/com/auth/login/ForgotPasswordForm.tsx:87 @@ -4253,22 +4065,22 @@ msgstr "" #: src/view/com/auth/login/LoginForm.tsx:118 #: src/view/com/modals/ChangePassword.tsx:70 msgid "Unable to contact your service. Please check your Internet connection." -msgstr "" +msgstr "Es ist uns nicht gelungen, deinen Dienst zu kontaktieren. Bitte überprüfe deine Internetverbindung." #: src/view/com/profile/ProfileHeader.tsx:433 #: src/view/screens/ProfileList.tsx:590 msgid "Unblock" -msgstr "" +msgstr "Entblocken" #: src/view/com/profile/ProfileHeader.tsx:436 msgctxt "action" msgid "Unblock" -msgstr "" +msgstr "Entblocken" #: src/view/com/profile/ProfileHeader.tsx:261 #: src/view/com/profile/ProfileHeader.tsx:345 msgid "Unblock Account" -msgstr "" +msgstr "Konto entblocken" #: src/view/com/modals/Repost.tsx:42 #: src/view/com/modals/Repost.tsx:55 @@ -4280,58 +4092,58 @@ msgstr "Repost rückgängig machen" #: src/view/com/profile/FollowButton.tsx:55 msgctxt "action" msgid "Unfollow" -msgstr "" +msgstr "Nicht mehr folgen" #: src/view/com/profile/ProfileHeader.tsx:485 msgid "Unfollow {0}" -msgstr "" +msgstr "{0} nicht mehr folgen" #: src/view/com/auth/create/state.ts:262 msgid "Unfortunately, you do not meet the requirements to create an account." msgstr "Leider erfüllst du nicht die Voraussetzungen, um einen Account zu erstellen." #: src/view/com/util/post-ctrls/PostCtrls.tsx:182 -#: src/view/com/util/post-ctrls/PostCtrls.tsx:216 msgid "Unlike" -msgstr "" +msgstr "Like aufheben" -#: src/components/TagMenu/index.tsx:253 +#: src/components/TagMenu/index.tsx:249 #: src/view/screens/ProfileList.tsx:597 msgid "Unmute" -msgstr "" +msgstr "Stummschaltung aufheben" -#: src/components/TagMenu/index.web.tsx:90 +#: src/components/TagMenu/index.web.tsx:104 msgid "Unmute {truncatedTag}" -msgstr "" +msgstr "Stummschaltung von {truncatedTag} aufheben" #: src/view/com/profile/ProfileHeader.tsx:326 msgid "Unmute Account" -msgstr "" +msgstr "Stummschaltung von Konto aufheben" -#: src/components/TagMenu/index.tsx:210 -msgid "Unmute all {tag} posts" -msgstr "" +#: src/components/TagMenu/index.tsx:208 +msgid "Unmute all {displayTag} posts" +msgstr "Stummschaltung aller {displayTag}-Beiträge aufheben" -#: src/view/com/util/forms/PostDropdownBtn.tsx:202 +#: src/view/com/util/forms/PostDropdownBtn.tsx:251 +#: src/view/com/util/forms/PostDropdownBtn.tsx:256 msgid "Unmute thread" -msgstr "" +msgstr "Stummschaltung von Thread aufheben" #: src/view/screens/ProfileFeed.tsx:354 #: src/view/screens/ProfileList.tsx:581 msgid "Unpin" -msgstr "" +msgstr "Anheften aufheben" #: src/view/screens/ProfileList.tsx:474 msgid "Unpin moderation list" -msgstr "" +msgstr "Anheften der Moderationsliste aufheben" #: src/view/screens/ProfileFeed.tsx:346 msgid "Unsave" -msgstr "" +msgstr "Speicherung aufheben" #: src/view/com/modals/UserAddRemoveLists.tsx:70 msgid "Update {displayName} in Lists" -msgstr "" +msgstr "{displayName} in Listen aktualisieren" #: src/lib/hooks/useOTAUpdate.ts:15 msgid "Update Available" @@ -4343,7 +4155,7 @@ msgstr "Aktualisieren..." #: src/view/com/modals/ChangeHandle.tsx:455 msgid "Upload a text file to:" -msgstr "" +msgstr "Hochladen einer Textdatei auf:" #: src/view/screens/AppPasswords.tsx:195 msgid "Use app passwords to login to other Bluesky clients without giving full access to your account or password." @@ -4356,36 +4168,32 @@ msgstr "Standardanbieter verwenden" #: src/view/com/modals/InAppBrowserConsent.tsx:56 #: src/view/com/modals/InAppBrowserConsent.tsx:58 msgid "Use in-app browser" -msgstr "" +msgstr "In-App-Browser verwenden" #: src/view/com/modals/InAppBrowserConsent.tsx:66 #: src/view/com/modals/InAppBrowserConsent.tsx:68 msgid "Use my default browser" -msgstr "" +msgstr "Meinen Standardbrowser verwenden" #: src/view/com/modals/AddAppPasswords.tsx:155 msgid "Use this to sign into the other app along with your handle." msgstr "Verwenden dies, um dich mit deinem Handle bei der anderen App einzuloggen." -#: src/view/com/modals/ServerInput.tsx:105 -#~ msgid "Use your domain as your Bluesky client service provider" -#~ msgstr "" - #: src/view/com/modals/InviteCodes.tsx:200 msgid "Used by:" msgstr "Verwendet von:" #: src/view/com/modals/ModerationDetails.tsx:54 msgid "User Blocked" -msgstr "" +msgstr "Benutzer blockiert" #: src/view/com/modals/ModerationDetails.tsx:40 msgid "User Blocked by List" -msgstr "" +msgstr "Benutzer durch der Liste blockiert" #: src/view/com/modals/ModerationDetails.tsx:60 msgid "User Blocks You" -msgstr "" +msgstr "Benutzer blockiert dich" #: src/view/com/auth/create/Step2.tsx:79 msgid "User handle" @@ -4394,25 +4202,25 @@ msgstr "Benutzerhandle" #: src/view/com/lists/ListCard.tsx:85 #: src/view/com/modals/UserAddRemoveLists.tsx:198 msgid "User list by {0}" -msgstr "" +msgstr "Benutzerliste von {0}" -#: src/view/screens/ProfileList.tsx:762 +#: src/view/screens/ProfileList.tsx:763 msgid "User list by <0/>" -msgstr "" +msgstr "Benutzerliste von <0/>" #: src/view/com/lists/ListCard.tsx:83 #: src/view/com/modals/UserAddRemoveLists.tsx:196 -#: src/view/screens/ProfileList.tsx:760 +#: src/view/screens/ProfileList.tsx:761 msgid "User list by you" -msgstr "" +msgstr "Benutzerliste von dir" #: src/view/com/modals/CreateOrEditList.tsx:196 msgid "User list created" -msgstr "" +msgstr "Benutzerliste erstellt" #: src/view/com/modals/CreateOrEditList.tsx:182 msgid "User list updated" -msgstr "" +msgstr "Benutzerliste aktualisiert" #: src/view/screens/Lists.tsx:58 msgid "User Lists" @@ -4423,7 +4231,7 @@ msgstr "Benutzerlisten" msgid "Username or email address" msgstr "Benutzername oder E-Mail-Adresse" -#: src/view/screens/ProfileList.tsx:796 +#: src/view/screens/ProfileList.tsx:797 msgid "Users" msgstr "Benutzer" @@ -4433,11 +4241,7 @@ msgstr "Nutzer gefolgt von <0/>" #: src/view/com/modals/Threadgate.tsx:106 msgid "Users in \"{0}\"" -msgstr "" - -#: src/view/com/auth/create/Step2.tsx:243 -#~ msgid "Verification code" -#~ msgstr "" +msgstr "Benutzer in \"{0}\"" #: src/view/screens/Settings/index.tsx:910 msgid "Verify email" @@ -4458,15 +4262,15 @@ msgstr "Neue E-Mail bestätigen" #: src/view/com/modals/VerifyEmail.tsx:103 msgid "Verify Your Email" -msgstr "" +msgstr "Überprüfe deine E-Mail" #: src/screens/Onboarding/index.tsx:42 msgid "Video Games" -msgstr "" +msgstr "Videospiele" #: src/view/com/profile/ProfileHeader.tsx:662 msgid "View {0}'s avatar" -msgstr "" +msgstr "Avatar {0} ansehen" #: src/view/screens/Log.tsx:52 msgid "View debug entry" @@ -4474,11 +4278,11 @@ msgstr "Debug-Eintrag anzeigen" #: src/view/com/posts/FeedSlice.tsx:103 msgid "View full thread" -msgstr "" +msgstr "Vollständigen Thread ansehen" #: src/view/com/posts/FeedErrorMessage.tsx:172 msgid "View profile" -msgstr "" +msgstr "Profil ansehen" #: src/view/com/profile/ProfileSubpageHeader.tsx:128 msgid "View the avatar" @@ -4491,51 +4295,51 @@ msgstr "Seite ansehen" #: src/screens/Onboarding/StepModeration/ModerationOption.tsx:42 #: src/view/com/modals/ContentFilteringSettings.tsx:259 msgid "Warn" -msgstr "" +msgstr "Warnen" #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:134 msgid "We also think you'll like \"For You\" by Skygaze:" -msgstr "" +msgstr "Wir glauben auch, dass dir \"For You\" von Skygaze gefallen wird:" + +#: src/screens/Hashtag.tsx:132 +msgid "We couldn't find any results for that hashtag." +msgstr "Wir konnten keine Ergebnisse für diesen Hashtag finden." #: src/screens/Deactivated.tsx:133 msgid "We estimate {estimatedTime} until your account is ready." -msgstr "" +msgstr "Wir schätzen {estimatedTime} bis dein Konto bereit ist." #: src/screens/Onboarding/StepFinished.tsx:93 msgid "We hope you have a wonderful time. Remember, Bluesky is:" -msgstr "" +msgstr "Wir hoffen, dass du eine schöne Zeit hast. Denke daran, Bluesky ist:" #: src/view/com/posts/DiscoverFallbackHeader.tsx:29 msgid "We ran out of posts from your follows. Here's the latest from <0/>." -msgstr "" - -#: src/screens/Onboarding/StepAlgoFeeds/index.tsx:118 -#~ msgid "We recommend \"For You\" by Skygaze:" -#~ msgstr "" +msgstr "Wir haben keine Beiträge mehr von den Konten, denen du folgst. Hier ist das Neueste von <0/>." -#: src/components/dialogs/MutedWords.tsx:161 +#: src/components/dialogs/MutedWords.tsx:204 msgid "We recommend avoiding common words that appear in many posts, since it can result in no posts being shown." -msgstr "" +msgstr "Wir empfehlen, gebräuchliche Wörter zu vermeiden, die in vielen Beiträgen vorkommen, da dies dazu führen kann, dass keine Beiträge angezeigt werden." #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:124 msgid "We recommend our \"Discover\" feed:" -msgstr "" +msgstr "Wir empfehlen unser \"Discover\" Feed:" #: src/screens/Onboarding/StepInterests/index.tsx:133 msgid "We weren't able to connect. Please try again to continue setting up your account. If it continues to fail, you can skip this flow." -msgstr "" +msgstr "Die Verbindung konnte nicht hergestellt werden. Bitte versuche es erneut, um mit der Einrichtung deines Kontos fortzufahren. Wenn der Versuch weiterhin fehlschlägt, kannst du diesen Schritt überspringen." #: src/screens/Deactivated.tsx:137 msgid "We will let you know when your account is ready." -msgstr "" +msgstr "Wir werden dich benachrichtigen, wenn dein Konto bereit ist." #: src/view/com/modals/AppealLabel.tsx:48 msgid "We'll look into your appeal promptly." -msgstr "" +msgstr "Wir werden deinen Widerspruch unverzüglich prüfen." #: src/screens/Onboarding/StepInterests/index.tsx:138 msgid "We'll use this to help customize your experience." -msgstr "" +msgstr "Wir verwenden diese Informationen, um dein Erlebnis individuell zu gestalten." #: src/view/com/auth/create/CreateAccount.tsx:134 msgid "We're so excited to have you join us!" @@ -4543,16 +4347,17 @@ msgstr "Wir freuen uns sehr, dass du dabei bist!" #: src/view/screens/ProfileList.tsx:86 msgid "We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @{handleOrDid}." -msgstr "" +msgstr "Es tut uns leid, aber wir waren nicht in der Lage, diese Liste aufzulösen. Wenn das Problem weiterhin besteht, kontaktiere bitte den Ersteller der Liste, @{handleOrDid}." -#: src/components/dialogs/MutedWords.tsx:182 +#: src/components/dialogs/MutedWords.tsx:230 msgid "We're sorry, but we weren't able to load your muted words at this time. Please try again." -msgstr "" +msgstr "Es tut uns leid, aber wir konnten deine stummgeschalteten Wörter nicht laden. Bitte versuche es erneut." #: src/view/screens/Search/Search.tsx:254 msgid "We're sorry, but your search could not be completed. Please try again in a few minutes." msgstr "Es tut uns leid, aber deine Suche konnte nicht abgeschlossen werden. Bitte versuche es in ein paar Minuten erneut." +#: src/components/Lists.tsx:211 #: src/view/screens/NotFound.tsx:48 msgid "We're sorry! We can't find the page you were looking for." msgstr "Es tut uns leid! Wir können die Seite, nach der du gesucht hast, nicht finden." @@ -4563,11 +4368,11 @@ msgstr "Willkommen bei <0>Bluesky</0>" #: src/screens/Onboarding/StepInterests/index.tsx:130 msgid "What are your interests?" -msgstr "" +msgstr "Was sind deine Interessen?" #: src/view/com/modals/report/Modal.tsx:169 msgid "What is the issue with this {collectionName}?" -msgstr "" +msgstr "Was ist das Problem mit diesem {collectionName}?" #: src/view/com/auth/SplashScreen.tsx:59 #: src/view/com/composer/Composer.tsx:286 @@ -4602,11 +4407,7 @@ msgstr "Schreibe deine Antwort" #: src/screens/Onboarding/index.tsx:28 msgid "Writers" -msgstr "" - -#: src/view/com/auth/create/Step2.tsx:263 -#~ msgid "XXXXXX" -#~ msgstr "" +msgstr "Schriftsteller" #: src/view/com/composer/select-language/SuggestedLanguage.tsx:77 #: src/view/screens/PreferencesFollowingFeed.tsx:129 @@ -4618,26 +4419,18 @@ msgstr "" msgid "Yes" msgstr "Ja" -#: src/screens/Onboarding/StepModeration/index.tsx:46 -#~ msgid "You are in control" -#~ msgstr "" - #: src/screens/Deactivated.tsx:130 msgid "You are in line." -msgstr "" +msgstr "Du befindest dich in der Warteschlange." #: src/view/com/posts/FollowingEmptyState.tsx:67 #: src/view/com/posts/FollowingEndOfFeed.tsx:68 msgid "You can also discover new Custom Feeds to follow." -msgstr "" - -#: src/screens/Onboarding/StepAlgoFeeds/index.tsx:123 -#~ msgid "You can also try our \"Discover\" algorithm:" -#~ msgstr "" +msgstr "Du kannst auch neue benutzerdefinierte Feeds entdecken und ihnen folgen." #: src/screens/Onboarding/StepFollowingFeed.tsx:142 msgid "You can change these settings later." -msgstr "" +msgstr "Du kannst diese Einstellungen später ändern." #: src/view/com/auth/login/Login.tsx:158 #: src/view/com/auth/login/PasswordUpdatedForm.tsx:31 @@ -4666,18 +4459,18 @@ msgstr "Du hast den Verfasser blockiert oder du wurdest vom Verfasser blockiert. #: src/view/com/modals/ModerationDetails.tsx:56 msgid "You have blocked this user. You cannot view their content." -msgstr "" +msgstr "Du hast diesen Benutzer blockiert und kannst seine Inhalte nicht sehen." #: src/view/com/auth/login/SetNewPasswordForm.tsx:57 #: src/view/com/auth/login/SetNewPasswordForm.tsx:92 #: src/view/com/modals/ChangePassword.tsx:87 #: src/view/com/modals/ChangePassword.tsx:121 msgid "You have entered an invalid code. It should look like XXXXX-XXXXX." -msgstr "" +msgstr "Du hast einen ungültigen Code eingegeben. Er sollte wie XXXXX-XXXXX aussehen." #: src/view/com/modals/ModerationDetails.tsx:87 msgid "You have muted this user." -msgstr "" +msgstr "Du hast diesen Benutzer stummgeschaltet." #: src/view/com/feeds/ProfileFeedgens.tsx:136 msgid "You have no feeds." @@ -4690,7 +4483,7 @@ msgstr "Du hast keine Listen." #: src/view/screens/ModerationBlockedAccounts.tsx:132 msgid "You have not blocked any accounts yet. To block an account, go to their profile and selected \"Block account\" from the menu on their account." -msgstr "" +msgstr "Du hast noch keine Konten blockiert. Um ein Konto zu blockieren, gehe auf dessen Profil und wähle \"Konto blockieren\" aus dem Menü des Kontos aus." #: src/view/screens/AppPasswords.tsx:87 msgid "You have not created any app passwords yet. You can create one by pressing the button below." @@ -4698,27 +4491,27 @@ msgstr "Du hast noch keine App-Passwörter erstellt. Du kannst eines erstellen, #: src/view/screens/ModerationMutedAccounts.tsx:131 msgid "You have not muted any accounts yet. To mute an account, go to their profile and selected \"Mute account\" from the menu on their account." -msgstr "" +msgstr "Du hast noch keine Konten stummgeschaltet. Um ein Konto stumm zu schalten, gehe auf dessen Profil und wähle \"Konto stummschalten\" aus dem Menü des Kontos aus." -#: src/components/dialogs/MutedWords.tsx:202 +#: src/components/dialogs/MutedWords.tsx:250 msgid "You haven't muted any words or tags yet" -msgstr "" +msgstr "Du hast noch keine Wörter oder Tags stummgeschaltet" #: src/view/com/modals/ContentFilteringSettings.tsx:175 msgid "You must be 18 or older to enable adult content." -msgstr "" +msgstr "Du musst 18 Jahre oder älter sein, um Inhalte für Erwachsene zu aktivieren." #: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:103 msgid "You must be 18 years or older to enable adult content" -msgstr "" +msgstr "Du musst 18 Jahre oder älter sein, um Inhalte für Erwachsene zu aktivieren." -#: src/view/com/util/forms/PostDropdownBtn.tsx:129 +#: src/view/com/util/forms/PostDropdownBtn.tsx:147 msgid "You will no longer receive notifications for this thread" -msgstr "" +msgstr "Du wirst keine Mitteilungen mehr für diesen Thread erhalten" -#: src/view/com/util/forms/PostDropdownBtn.tsx:132 +#: src/view/com/util/forms/PostDropdownBtn.tsx:150 msgid "You will now receive notifications for this thread" -msgstr "" +msgstr "Du erhälst nun Mitteilungen für dieses Thread" #: src/view/com/auth/login/SetNewPasswordForm.tsx:107 msgid "You will receive an email with a \"reset code.\" Enter that code here, then enter your new password." @@ -4726,45 +4519,45 @@ msgstr "Du erhältst eine E-Mail mit einem \"Reset-Code\". Gib diesen Code hier #: src/screens/Onboarding/StepModeration/index.tsx:72 msgid "You're in control" -msgstr "" +msgstr "Du hast die Kontrolle" #: src/screens/Deactivated.tsx:87 #: src/screens/Deactivated.tsx:88 #: src/screens/Deactivated.tsx:103 msgid "You're in line" -msgstr "" +msgstr "Du bist in der Warteschlange" #: src/screens/Onboarding/StepFinished.tsx:90 msgid "You're ready to go!" -msgstr "" +msgstr "Du kannst loslegen!" #: src/view/com/posts/FollowingEndOfFeed.tsx:48 msgid "You've reached the end of your feed! Find some more accounts to follow." -msgstr "" +msgstr "Du hast das Ende deines Feeds erreicht! Finde weitere Konten, denen du folgen kannst." -#: src/view/com/auth/create/Step1.tsx:74 +#: src/view/com/auth/create/Step1.tsx:67 msgid "Your account" msgstr "Dein Konto" #: src/view/com/modals/DeleteAccount.tsx:67 msgid "Your account has been deleted" -msgstr "" +msgstr "Dein Konto wurde gelöscht" #: src/view/screens/Settings/ExportCarDialog.tsx:47 msgid "Your account repository, containing all public data records, can be downloaded as a \"CAR\" file. This file does not include media embeds, such as images, or your private data, which must be fetched separately." -msgstr "" +msgstr "Dein Kontodepot, das alle öffentlichen Datensätze enthält, kann als \"CAR\"-Datei heruntergeladen werden. Diese Datei enthält keine Medieneinbettungen, wie z. B. Bilder, oder deine privaten Daten, welche separat abgerufen werden müssen." -#: src/view/com/auth/create/Step1.tsx:238 +#: src/view/com/auth/create/Step1.tsx:215 msgid "Your birth date" msgstr "Dein Geburtsdatum" #: src/view/com/modals/InAppBrowserConsent.tsx:47 msgid "Your choice will be saved, but can be changed later in settings." -msgstr "" +msgstr "Deine Wahl wird gespeichert, kann aber später in den Einstellungen geändert werden." #: src/screens/Onboarding/StepFollowingFeed.tsx:61 msgid "Your default feed is \"Following\"" -msgstr "" +msgstr "Dein Standard-Feed ist \"Following\"" #: src/view/com/auth/create/state.ts:110 #: src/view/com/auth/login/ForgotPasswordForm.tsx:70 @@ -4772,10 +4565,6 @@ msgstr "" msgid "Your email appears to be invalid." msgstr "Deine E-Mail scheint ungültig zu sein." -#: src/view/com/modals/Waitlist.tsx:109 -msgid "Your email has been saved! We'll be in touch soon." -msgstr "Deine E-Mail wurde gespeichert! Wir werden uns bald bei dir melden." - #: src/view/com/modals/ChangeEmail.tsx:125 msgid "Your email has been updated but not verified. As a next step, please verify your new email." msgstr "Deine E-Mail wurde aktualisiert, aber nicht bestätigt. Als nächsten Schritt bestätige bitte deine neue E-Mail." @@ -4786,33 +4575,27 @@ msgstr "Deine E-Mail wurde noch nicht bestätigt. Dies ist ein wichtiger Sicherh #: src/view/com/posts/FollowingEmptyState.tsx:47 msgid "Your following feed is empty! Follow more users to see what's happening." -msgstr "" +msgstr "Dein Following-Feed ist leer! Folge mehr Benutzern, um auf dem Laufenden zu bleiben." #: src/view/com/auth/create/Step2.tsx:83 msgid "Your full handle will be" -msgstr "" +msgstr "Dein vollständiger Handle lautet" #: src/view/com/modals/ChangeHandle.tsx:270 msgid "Your full handle will be <0>@{0}</0>" -msgstr "" +msgstr "Dein vollständiger Handle lautet <0>@{0}</0>" -#: src/view/screens/Settings.tsx:430 -#: src/view/shell/desktop/RightNav.tsx:137 -#: src/view/shell/Drawer.tsx:660 -#~ msgid "Your invite codes are hidden when logged in using an App Password" -#~ msgstr "Deine Einladungscodes werden ausgeblendet, wenn du dich mit einem App-Passwort anmeldest" - -#: src/components/dialogs/MutedWords.tsx:173 +#: src/components/dialogs/MutedWords.tsx:221 msgid "Your muted words" -msgstr "" +msgstr "Deine stummgeschalteten Wörter" #: src/view/com/modals/ChangePassword.tsx:155 msgid "Your password has been changed successfully!" -msgstr "" +msgstr "Dein Passwort wurde erfolgreich geändert!" #: src/view/com/composer/Composer.tsx:274 msgid "Your post has been published" -msgstr "" +msgstr "Dein Beitrag wurde veröffentlicht" #: src/screens/Onboarding/StepFinished.tsx:105 #: src/view/com/auth/onboarding/WelcomeDesktop.tsx:59 @@ -4827,7 +4610,7 @@ msgstr "Dein Profil" #: src/view/com/composer/Composer.tsx:273 msgid "Your reply has been published" -msgstr "" +msgstr "Deine Antwort wurde veröffentlicht" #: src/view/com/auth/create/Step2.tsx:65 msgid "Your user handle" diff --git a/src/locale/locales/en/messages.po b/src/locale/locales/en/messages.po index 8cdf8ebfa..b62c47ffc 100644 --- a/src/locale/locales/en/messages.po +++ b/src/locale/locales/en/messages.po @@ -75,12 +75,12 @@ msgstr "" msgid "A new version of the app is available. Please update to continue using the app." msgstr "" -#: src/view/com/util/ViewHeader.tsx:83 +#: src/view/com/util/ViewHeader.tsx:89 #: src/view/screens/Search/Search.tsx:647 msgid "Access navigation links and settings" msgstr "" -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:51 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:52 msgid "Access profile and other navigation links" msgstr "" @@ -127,11 +127,11 @@ msgstr "" msgid "Account unmuted" msgstr "" -#: src/components/dialogs/MutedWords.tsx:147 +#: src/components/dialogs/MutedWords.tsx:165 #: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:150 #: src/view/com/modals/ListAddRemoveUsers.tsx:264 #: src/view/com/modals/UserAddRemoveLists.tsx:219 -#: src/view/screens/ProfileList.tsx:812 +#: src/view/screens/ProfileList.tsx:813 msgid "Add" msgstr "" @@ -139,7 +139,7 @@ msgstr "" msgid "Add a content warning" msgstr "" -#: src/view/screens/ProfileList.tsx:802 +#: src/view/screens/ProfileList.tsx:803 msgid "Add a user to this list" msgstr "" @@ -177,11 +177,11 @@ msgstr "" msgid "Add link card:" msgstr "" -#: src/components/dialogs/MutedWords.tsx:140 +#: src/components/dialogs/MutedWords.tsx:158 msgid "Add mute word for configured settings" msgstr "" -#: src/components/dialogs/MutedWords.tsx:74 +#: src/components/dialogs/MutedWords.tsx:87 msgid "Add muted words and tags" msgstr "" @@ -269,7 +269,7 @@ msgstr "" msgid "An issue occurred, please try again." msgstr "" -#: src/view/com/notifications/FeedItem.tsx:236 +#: src/view/com/notifications/FeedItem.tsx:237 #: src/view/com/threadgate/WhoCanReply.tsx:178 msgid "and" msgstr "" @@ -302,13 +302,14 @@ msgstr "" #~ msgid "App passwords" #~ msgstr "" -#: src/Navigation.tsx:237 +#: src/Navigation.tsx:239 #: src/view/screens/AppPasswords.tsx:187 #: src/view/screens/Settings/index.tsx:684 msgid "App Passwords" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:295 +#: src/view/com/util/forms/PostDropdownBtn.tsx:337 +#: src/view/com/util/forms/PostDropdownBtn.tsx:346 msgid "Appeal content warning" msgstr "" @@ -336,12 +337,12 @@ msgstr "" msgid "Are you sure you'd like to discard this draft?" msgstr "" -#: src/components/dialogs/MutedWords.tsx:233 +#: src/components/dialogs/MutedWords.tsx:282 #: src/view/screens/ProfileList.tsx:365 msgid "Are you sure?" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:278 +#: src/view/com/util/forms/PostDropdownBtn.tsx:322 msgid "Are you sure? This cannot be undone." msgstr "" @@ -367,7 +368,7 @@ msgstr "" #: src/view/com/post-thread/PostThread.tsx:522 #: src/view/com/post-thread/PostThread.tsx:530 #: src/view/com/profile/ProfileHeader.tsx:649 -#: src/view/com/util/ViewHeader.tsx:81 +#: src/view/com/util/ViewHeader.tsx:87 msgid "Back" msgstr "" @@ -384,7 +385,7 @@ msgstr "" msgid "Basics" msgstr "" -#: src/view/com/auth/create/Step1.tsx:250 +#: src/view/com/auth/create/Step1.tsx:227 #: src/view/com/modals/BirthDateSettings.tsx:73 msgid "Birthday" msgstr "" @@ -423,7 +424,7 @@ msgstr "" msgid "Blocked accounts" msgstr "" -#: src/Navigation.tsx:130 +#: src/Navigation.tsx:132 #: src/view/screens/ModerationBlockedAccounts.tsx:107 msgid "Blocked Accounts" msgstr "" @@ -475,8 +476,8 @@ msgid "Bluesky is public." msgstr "" #: src/view/com/modals/Waitlist.tsx:70 -msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon." -msgstr "" +#~ msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon." +#~ msgstr "" #: src/view/screens/Moderation.tsx:245 msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private." @@ -529,7 +530,7 @@ msgstr "" msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must be at least 4 characters long, but no more than 32 characters long." msgstr "" -#: src/components/Prompt.tsx:91 +#: src/components/Prompt.tsx:101 #: src/view/com/composer/Composer.tsx:307 #: src/view/com/composer/Composer.tsx:312 #: src/view/com/modals/ChangeEmail.tsx:218 @@ -544,7 +545,6 @@ msgstr "" #: src/view/com/modals/Repost.tsx:87 #: src/view/com/modals/VerifyEmail.tsx:247 #: src/view/com/modals/VerifyEmail.tsx:253 -#: src/view/com/modals/Waitlist.tsx:142 #: src/view/screens/Search/Search.tsx:716 #: src/view/shell/desktop/Search.tsx:238 msgid "Cancel" @@ -586,8 +586,8 @@ msgid "Cancel search" msgstr "" #: src/view/com/modals/Waitlist.tsx:136 -msgid "Cancel waitlist signup" -msgstr "" +#~ msgid "Cancel waitlist signup" +#~ msgstr "" #: src/view/screens/Settings/index.tsx:334 msgctxt "action" @@ -673,7 +673,7 @@ msgstr "" msgid "Choose your main feeds" msgstr "" -#: src/view/com/auth/create/Step1.tsx:219 +#: src/view/com/auth/create/Step1.tsx:196 msgid "Choose your password" msgstr "" @@ -704,11 +704,14 @@ msgstr "" msgid "click here" msgstr "" -#: src/components/RichText.tsx:189 -#: src/components/TagMenu/index.web.tsx:125 +#: src/components/TagMenu/index.web.tsx:138 msgid "Click here to open tag menu for {tag}" msgstr "" +#: src/components/RichText.tsx:191 +msgid "Click here to open tag menu for #{tag}" +msgstr "" + #: src/screens/Onboarding/index.tsx:35 msgid "Climate" msgstr "" @@ -718,8 +721,8 @@ msgstr "" msgid "Close" msgstr "" -#: src/components/Dialog/index.web.tsx:80 -#: src/components/Dialog/index.web.tsx:194 +#: src/components/Dialog/index.web.tsx:84 +#: src/components/Dialog/index.web.tsx:198 msgid "Close active dialog" msgstr "" @@ -743,7 +746,7 @@ msgstr "" msgid "Close navigation footer" msgstr "" -#: src/components/TagMenu/index.tsx:266 +#: src/components/TagMenu/index.tsx:262 msgid "Close this dialog" msgstr "" @@ -763,7 +766,7 @@ msgstr "" msgid "Closes viewer for header image" msgstr "" -#: src/view/com/notifications/FeedItem.tsx:317 +#: src/view/com/notifications/FeedItem.tsx:318 msgid "Collapses list of users for a given notification" msgstr "" @@ -775,7 +778,7 @@ msgstr "" msgid "Comics" msgstr "" -#: src/Navigation.tsx:227 +#: src/Navigation.tsx:229 #: src/view/screens/CommunityGuidelines.tsx:32 msgid "Community Guidelines" msgstr "" @@ -800,7 +803,7 @@ msgstr "" msgid "Configure content filtering setting for category: {0}" msgstr "" -#: src/components/Prompt.tsx:113 +#: src/components/Prompt.tsx:124 #: src/view/com/modals/AppealLabel.tsx:98 #: src/view/com/modals/SelfLabel.tsx:154 #: src/view/com/modals/VerifyEmail.tsx:231 @@ -840,8 +843,8 @@ msgid "Confirmation code" msgstr "" #: src/view/com/modals/Waitlist.tsx:120 -msgid "Confirms signing up {email} to the waitlist" -msgstr "" +#~ msgid "Confirms signing up {email} to the waitlist" +#~ msgstr "" #: src/view/com/auth/create/CreateAccount.tsx:193 #: src/view/com/auth/login/LoginForm.tsx:278 @@ -918,7 +921,7 @@ msgstr "" #: src/view/com/modals/AddAppPasswords.tsx:76 #: src/view/com/modals/InviteCodes.tsx:152 -#: src/view/com/util/forms/PostDropdownBtn.tsx:143 +#: src/view/com/util/forms/PostDropdownBtn.tsx:161 msgid "Copied to clipboard" msgstr "" @@ -934,7 +937,8 @@ msgstr "" msgid "Copy link to list" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:184 +#: src/view/com/util/forms/PostDropdownBtn.tsx:231 +#: src/view/com/util/forms/PostDropdownBtn.tsx:237 msgid "Copy link to post" msgstr "" @@ -942,11 +946,12 @@ msgstr "" msgid "Copy link to profile" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:170 +#: src/view/com/util/forms/PostDropdownBtn.tsx:223 +#: src/view/com/util/forms/PostDropdownBtn.tsx:225 msgid "Copy post text" msgstr "" -#: src/Navigation.tsx:232 +#: src/Navigation.tsx:234 #: src/view/screens/CopyrightPolicy.tsx:29 msgid "Copyright Policy" msgstr "" @@ -955,7 +960,7 @@ msgstr "" msgid "Could not load feed" msgstr "" -#: src/view/screens/ProfileList.tsx:888 +#: src/view/screens/ProfileList.tsx:893 msgid "Could not load list" msgstr "" @@ -1075,11 +1080,12 @@ msgstr "" msgid "Delete My Account…" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:273 +#: src/view/com/util/forms/PostDropdownBtn.tsx:317 +#: src/view/com/util/forms/PostDropdownBtn.tsx:326 msgid "Delete post" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:277 +#: src/view/com/util/forms/PostDropdownBtn.tsx:321 msgid "Delete this post?" msgstr "" @@ -1148,8 +1154,8 @@ msgid "Domain verified!" msgstr "" #: src/view/com/auth/create/Step1.tsx:170 -msgid "Don't have an invite code?" -msgstr "" +#~ msgid "Don't have an invite code?" +#~ msgstr "" #: src/view/com/auth/onboarding/RecommendedFollows.tsx:86 #: src/view/com/modals/EditImage.tsx:333 @@ -1251,7 +1257,7 @@ msgstr "" msgid "Edit Moderation List" msgstr "" -#: src/Navigation.tsx:242 +#: src/Navigation.tsx:244 #: src/view/screens/Feeds.tsx:434 #: src/view/screens/SavedFeeds.tsx:84 msgid "Edit My Feeds" @@ -1269,7 +1275,7 @@ msgstr "" msgid "Edit Profile" msgstr "" -#: src/view/com/home/HomeHeaderLayout.web.tsx:59 +#: src/view/com/home/HomeHeaderLayout.web.tsx:62 #: src/view/screens/Feeds.tsx:355 msgid "Edit Saved Feeds" msgstr "" @@ -1290,14 +1296,13 @@ msgstr "" msgid "Education" msgstr "" -#: src/view/com/auth/create/Step1.tsx:199 +#: src/view/com/auth/create/Step1.tsx:176 #: src/view/com/auth/login/ForgotPasswordForm.tsx:156 #: src/view/com/modals/ChangeEmail.tsx:141 -#: src/view/com/modals/Waitlist.tsx:88 msgid "Email" msgstr "" -#: src/view/com/auth/create/Step1.tsx:190 +#: src/view/com/auth/create/Step1.tsx:167 #: src/view/com/auth/login/ForgotPasswordForm.tsx:147 msgid "Email address" msgstr "" @@ -1352,8 +1357,8 @@ msgstr "" msgid "Enter a name for this App Password" msgstr "" -#: src/components/dialogs/MutedWords.tsx:87 -#: src/components/dialogs/MutedWords.tsx:88 +#: src/components/dialogs/MutedWords.tsx:100 +#: src/components/dialogs/MutedWords.tsx:101 msgid "Enter a word or tag" msgstr "" @@ -1373,16 +1378,16 @@ msgstr "" msgid "Enter the email you used to create your account. We'll send you a \"reset code\" so you can set a new password." msgstr "" -#: src/view/com/auth/create/Step1.tsx:251 +#: src/view/com/auth/create/Step1.tsx:228 #: src/view/com/modals/BirthDateSettings.tsx:74 msgid "Enter your birth date" msgstr "" #: src/view/com/modals/Waitlist.tsx:78 -msgid "Enter your email" -msgstr "" +#~ msgid "Enter your email" +#~ msgstr "" -#: src/view/com/auth/create/Step1.tsx:195 +#: src/view/com/auth/create/Step1.tsx:172 msgid "Enter your email address" msgstr "" @@ -1428,8 +1433,8 @@ msgid "Exits inputting search query" msgstr "" #: src/view/com/modals/Waitlist.tsx:138 -msgid "Exits signing up for waitlist with {email}" -msgstr "" +#~ msgid "Exits signing up for waitlist with {email}" +#~ msgstr "" #: src/view/com/lightbox/Lightbox.web.tsx:163 msgid "Expand alt text" @@ -1458,7 +1463,7 @@ msgstr "" msgid "External media may allow websites to collect information about you and your device. No information is sent or requested until you press the \"play\" button." msgstr "" -#: src/Navigation.tsx:261 +#: src/Navigation.tsx:263 #: src/view/screens/PreferencesExternalEmbeds.tsx:52 #: src/view/screens/Settings/index.tsx:657 msgid "External Media Preferences" @@ -1477,7 +1482,7 @@ msgstr "" msgid "Failed to create the list. Check your internet connection and try again." msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:110 +#: src/view/com/util/forms/PostDropdownBtn.tsx:128 msgid "Failed to delete post, please try again" msgstr "" @@ -1486,7 +1491,7 @@ msgstr "" msgid "Failed to load recommended feeds" msgstr "" -#: src/Navigation.tsx:192 +#: src/Navigation.tsx:194 msgid "Feed" msgstr "" @@ -1507,7 +1512,7 @@ msgstr "" msgid "Feedback" msgstr "" -#: src/Navigation.tsx:445 +#: src/Navigation.tsx:452 #: src/view/screens/Feeds.tsx:419 #: src/view/screens/Feeds.tsx:524 #: src/view/screens/Profile.tsx:184 @@ -1648,9 +1653,9 @@ msgstr "" msgid "Following {0}" msgstr "" -#: src/Navigation.tsx:248 -#: src/view/com/home/HomeHeaderLayout.web.tsx:45 -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:83 +#: src/Navigation.tsx:250 +#: src/view/com/home/HomeHeaderLayout.web.tsx:50 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:84 #: src/view/screens/PreferencesFollowingFeed.tsx:104 #: src/view/screens/Settings/index.tsx:543 msgid "Following Feed Preferences" @@ -1689,6 +1694,11 @@ msgstr "" msgid "Forgot Password" msgstr "" +#: src/screens/Hashtag.tsx:108 +#: src/screens/Hashtag.tsx:148 +msgid "From @{sanitizedAuthor}" +msgstr "" + #: src/view/com/posts/FeedItem.tsx:189 msgctxt "from-feed" msgid "From <0/>" @@ -1712,8 +1722,8 @@ msgstr "" #: src/view/screens/ProfileFeed.tsx:106 #: src/view/screens/ProfileFeed.tsx:111 -#: src/view/screens/ProfileList.tsx:897 #: src/view/screens/ProfileList.tsx:902 +#: src/view/screens/ProfileList.tsx:907 msgid "Go Back" msgstr "" @@ -1739,8 +1749,16 @@ msgstr "" msgid "Handle" msgstr "" +#: src/Navigation.tsx:270 +msgid "Hashtag" +msgstr "" + #: src/components/RichText.tsx:188 -msgid "Hashtag: {tag}" +#~ msgid "Hashtag: {tag}" +#~ msgstr "" + +#: src/components/RichText.tsx:190 +msgid "Hashtag: #{tag}" msgstr "" #: src/view/com/auth/create/CreateAccount.tsx:208 @@ -1776,12 +1794,13 @@ msgid "Hide" msgstr "" #: src/view/com/modals/ContentFilteringSettings.tsx:224 -#: src/view/com/notifications/FeedItem.tsx:325 +#: src/view/com/notifications/FeedItem.tsx:326 msgctxt "action" msgid "Hide" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:232 +#: src/view/com/util/forms/PostDropdownBtn.tsx:276 +#: src/view/com/util/forms/PostDropdownBtn.tsx:287 msgid "Hide post" msgstr "" @@ -1790,11 +1809,11 @@ msgstr "" msgid "Hide the content" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:236 +#: src/view/com/util/forms/PostDropdownBtn.tsx:280 msgid "Hide this post?" msgstr "" -#: src/view/com/notifications/FeedItem.tsx:315 +#: src/view/com/notifications/FeedItem.tsx:316 msgid "Hide user list" msgstr "" @@ -1822,7 +1841,7 @@ msgstr "" msgid "Hmm, we're having trouble finding this feed. It may have been deleted." msgstr "" -#: src/Navigation.tsx:435 +#: src/Navigation.tsx:442 #: src/view/shell/bottom-bar/BottomBar.tsx:137 #: src/view/shell/desktop/LeftNav.tsx:306 #: src/view/shell/Drawer.tsx:398 @@ -1837,7 +1856,7 @@ msgstr "" #~ msgid "Home Feed Preferences" #~ msgstr "" -#: src/view/com/auth/create/Step1.tsx:82 +#: src/view/com/auth/create/Step1.tsx:75 #: src/view/com/auth/login/ForgotPasswordForm.tsx:120 msgid "Hosting provider" msgstr "" @@ -1891,11 +1910,11 @@ msgstr "" msgid "Input confirmation code for account deletion" msgstr "" -#: src/view/com/auth/create/Step1.tsx:200 +#: src/view/com/auth/create/Step1.tsx:177 msgid "Input email for Bluesky account" msgstr "" -#: src/view/com/auth/create/Step1.tsx:158 +#: src/view/com/auth/create/Step1.tsx:151 msgid "Input invite code to proceed" msgstr "" @@ -1928,8 +1947,8 @@ msgstr "" #~ msgstr "" #: src/view/com/modals/Waitlist.tsx:90 -msgid "Input your email to get on the Bluesky waitlist" -msgstr "" +#~ msgid "Input your email to get on the Bluesky waitlist" +#~ msgstr "" #: src/view/com/auth/login/LoginForm.tsx:229 msgid "Input your password" @@ -1955,8 +1974,8 @@ msgstr "" msgid "Invite a Friend" msgstr "" -#: src/view/com/auth/create/Step1.tsx:148 -#: src/view/com/auth/create/Step1.tsx:157 +#: src/view/com/auth/create/Step1.tsx:141 +#: src/view/com/auth/create/Step1.tsx:150 msgid "Invite code" msgstr "" @@ -1986,17 +2005,17 @@ msgid "Jobs" msgstr "" #: src/view/com/modals/Waitlist.tsx:67 -msgid "Join the waitlist" -msgstr "" +#~ msgid "Join the waitlist" +#~ msgstr "" #: src/view/com/auth/create/Step1.tsx:174 #: src/view/com/auth/create/Step1.tsx:178 -msgid "Join the waitlist." -msgstr "" +#~ msgid "Join the waitlist." +#~ msgstr "" #: src/view/com/modals/Waitlist.tsx:128 -msgid "Join Waitlist" -msgstr "" +#~ msgid "Join Waitlist" +#~ msgstr "" #: src/screens/Onboarding/index.tsx:24 msgid "Journalism" @@ -2010,7 +2029,7 @@ msgstr "" msgid "Language settings" msgstr "" -#: src/Navigation.tsx:140 +#: src/Navigation.tsx:142 #: src/view/screens/LanguageSettings.tsx:89 msgid "Language Settings" msgstr "" @@ -2080,7 +2099,6 @@ msgid "Light" msgstr "" #: src/view/com/util/post-ctrls/PostCtrls.tsx:182 -#: src/view/com/util/post-ctrls/PostCtrls.tsx:216 msgid "Like" msgstr "" @@ -2088,7 +2106,7 @@ msgstr "" msgid "Like this feed" msgstr "" -#: src/Navigation.tsx:197 +#: src/Navigation.tsx:199 msgid "Liked by" msgstr "" @@ -2121,7 +2139,7 @@ msgstr "" msgid "Likes on this post" msgstr "" -#: src/Navigation.tsx:166 +#: src/Navigation.tsx:168 msgid "List" msgstr "" @@ -2157,7 +2175,7 @@ msgstr "" msgid "List unmuted" msgstr "" -#: src/Navigation.tsx:110 +#: src/Navigation.tsx:112 #: src/view/screens/Profile.tsx:185 #: src/view/shell/desktop/LeftNav.tsx:379 #: src/view/shell/Drawer.tsx:492 @@ -2189,7 +2207,7 @@ msgstr "" #~ msgid "Local dev server" #~ msgstr "" -#: src/Navigation.tsx:207 +#: src/Navigation.tsx:209 msgid "Log" msgstr "" @@ -2212,7 +2230,7 @@ msgstr "" msgid "Make sure this is where you intend to go!" msgstr "" -#: src/components/dialogs/MutedWords.tsx:71 +#: src/components/dialogs/MutedWords.tsx:83 msgid "Manage your muted words and tags" msgstr "" @@ -2236,7 +2254,7 @@ msgstr "" msgid "Mentioned users" msgstr "" -#: src/view/com/util/ViewHeader.tsx:81 +#: src/view/com/util/ViewHeader.tsx:87 #: src/view/screens/Search/Search.tsx:646 msgid "Menu" msgstr "" @@ -2245,7 +2263,7 @@ msgstr "" msgid "Message from server: {0}" msgstr "" -#: src/Navigation.tsx:115 +#: src/Navigation.tsx:117 #: src/view/screens/Moderation.tsx:66 #: src/view/screens/Settings/index.tsx:625 #: src/view/shell/desktop/LeftNav.tsx:397 @@ -2259,13 +2277,13 @@ msgstr "" msgid "Moderation list by {0}" msgstr "" -#: src/view/screens/ProfileList.tsx:774 +#: src/view/screens/ProfileList.tsx:775 msgid "Moderation list by <0/>" msgstr "" #: src/view/com/lists/ListCard.tsx:91 #: src/view/com/modals/UserAddRemoveLists.tsx:204 -#: src/view/screens/ProfileList.tsx:772 +#: src/view/screens/ProfileList.tsx:773 msgid "Moderation list by you" msgstr "" @@ -2281,7 +2299,7 @@ msgstr "" msgid "Moderation lists" msgstr "" -#: src/Navigation.tsx:120 +#: src/Navigation.tsx:122 #: src/view/screens/ModerationModlists.tsx:58 msgid "Moderation Lists" msgstr "" @@ -2294,7 +2312,7 @@ msgstr "" msgid "Moderator has chosen to set a general warning on the content." msgstr "" -#: src/view/shell/desktop/Feeds.tsx:63 +#: src/view/shell/desktop/Feeds.tsx:65 msgid "More feeds" msgstr "" @@ -2305,8 +2323,8 @@ msgid "More options" msgstr "" #: src/view/com/util/forms/PostDropdownBtn.tsx:315 -msgid "More post options" -msgstr "" +#~ msgid "More post options" +#~ msgstr "" #: src/view/screens/PreferencesThreads.tsx:82 msgid "Most-liked replies first" @@ -2316,11 +2334,11 @@ msgstr "" msgid "Must be at least 3 characters" msgstr "" -#: src/components/TagMenu/index.tsx:253 +#: src/components/TagMenu/index.tsx:249 msgid "Mute" msgstr "" -#: src/components/TagMenu/index.web.tsx:91 +#: src/components/TagMenu/index.web.tsx:105 msgid "Mute {truncatedTag}" msgstr "" @@ -2332,15 +2350,19 @@ msgstr "" msgid "Mute accounts" msgstr "" -#: src/components/TagMenu/index.tsx:211 -msgid "Mute all {tag} posts" +#: src/components/TagMenu/index.tsx:209 +msgid "Mute all {displayTag} posts" msgstr "" -#: src/components/dialogs/MutedWords.tsx:131 +#: src/components/TagMenu/index.tsx:211 +#~ msgid "Mute all {tag} posts" +#~ msgstr "" + +#: src/components/dialogs/MutedWords.tsx:149 msgid "Mute in tags only" msgstr "" -#: src/components/dialogs/MutedWords.tsx:116 +#: src/components/dialogs/MutedWords.tsx:134 msgid "Mute in text & tags" msgstr "" @@ -2356,19 +2378,21 @@ msgstr "" msgid "Mute this List" msgstr "" -#: src/components/dialogs/MutedWords.tsx:109 +#: src/components/dialogs/MutedWords.tsx:127 msgid "Mute this word in post text and tags" msgstr "" -#: src/components/dialogs/MutedWords.tsx:124 +#: src/components/dialogs/MutedWords.tsx:142 msgid "Mute this word in tags only" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:202 +#: src/view/com/util/forms/PostDropdownBtn.tsx:251 +#: src/view/com/util/forms/PostDropdownBtn.tsx:257 msgid "Mute thread" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:216 +#: src/view/com/util/forms/PostDropdownBtn.tsx:267 +#: src/view/com/util/forms/PostDropdownBtn.tsx:269 msgid "Mute words & tags" msgstr "" @@ -2380,7 +2404,7 @@ msgstr "" msgid "Muted accounts" msgstr "" -#: src/Navigation.tsx:125 +#: src/Navigation.tsx:127 #: src/view/screens/ModerationMutedAccounts.tsx:107 msgid "Muted Accounts" msgstr "" @@ -2456,7 +2480,7 @@ msgstr "" msgid "Never lose access to your followers or data." msgstr "" -#: src/components/dialogs/MutedWords.tsx:244 +#: src/components/dialogs/MutedWords.tsx:293 msgid "Nevermind" msgstr "" @@ -2544,7 +2568,7 @@ msgid "No" msgstr "" #: src/view/screens/ProfileFeed.tsx:584 -#: src/view/screens/ProfileList.tsx:754 +#: src/view/screens/ProfileList.tsx:755 msgid "No description" msgstr "" @@ -2561,6 +2585,10 @@ msgstr "" msgid "No result" msgstr "" +#: src/components/Lists.tsx:192 +msgid "No results found" +msgstr "" + #: src/view/screens/Feeds.tsx:495 msgid "No results found for \"{query}\"" msgstr "" @@ -2583,7 +2611,7 @@ msgstr "" msgid "Not Applicable." msgstr "" -#: src/Navigation.tsx:105 +#: src/Navigation.tsx:107 #: src/view/screens/Profile.tsx:106 msgid "Not Found" msgstr "" @@ -2597,7 +2625,7 @@ msgstr "" msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites." msgstr "" -#: src/Navigation.tsx:450 +#: src/Navigation.tsx:457 #: src/view/screens/Notifications.tsx:124 #: src/view/screens/Notifications.tsx:148 #: src/view/shell/bottom-bar/BottomBar.tsx:205 @@ -2639,6 +2667,11 @@ msgstr "" msgid "Only {0} can reply." msgstr "" +#: src/components/Lists.tsx:82 +msgid "Oops, something went wrong!" +msgstr "" + +#: src/components/Lists.tsx:188 #: src/view/screens/AppPasswords.tsx:65 #: src/view/screens/Profile.tsx:106 msgid "Oops!" @@ -2665,10 +2698,14 @@ msgstr "" msgid "Open muted words settings" msgstr "" -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:49 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:50 msgid "Open navigation" msgstr "" +#: src/view/com/util/forms/PostDropdownBtn.tsx:175 +msgid "Open post options menu" +msgstr "" + #: src/view/screens/Settings/index.tsx:804 msgid "Open storybook page" msgstr "" @@ -2681,7 +2718,7 @@ msgstr "" msgid "Opens additional details for a debug entry" msgstr "" -#: src/view/com/notifications/FeedItem.tsx:348 +#: src/view/com/notifications/FeedItem.tsx:349 msgid "Opens an expanded list of users in this notification" msgstr "" @@ -2741,7 +2778,7 @@ msgstr "" msgid "Opens password reset form" msgstr "" -#: src/view/com/home/HomeHeaderLayout.web.tsx:60 +#: src/view/com/home/HomeHeaderLayout.web.tsx:63 #: src/view/screens/Feeds.tsx:356 msgid "Opens screen to edit Saved Feeds" msgstr "" @@ -2790,6 +2827,7 @@ msgstr "" msgid "Other..." msgstr "" +#: src/components/Lists.tsx:194 #: src/view/screens/NotFound.tsx:45 msgid "Page not found" msgstr "" @@ -2798,8 +2836,8 @@ msgstr "" msgid "Page Not Found" msgstr "" -#: src/view/com/auth/create/Step1.tsx:214 -#: src/view/com/auth/create/Step1.tsx:224 +#: src/view/com/auth/create/Step1.tsx:191 +#: src/view/com/auth/create/Step1.tsx:201 #: src/view/com/auth/login/LoginForm.tsx:226 #: src/view/com/auth/login/SetNewPasswordForm.tsx:161 #: src/view/com/modals/DeleteAccount.tsx:202 @@ -2814,11 +2852,11 @@ msgstr "" msgid "Password updated!" msgstr "" -#: src/Navigation.tsx:160 +#: src/Navigation.tsx:162 msgid "People followed by @{0}" msgstr "" -#: src/Navigation.tsx:153 +#: src/Navigation.tsx:155 msgid "People following @{0}" msgstr "" @@ -2892,6 +2930,10 @@ msgstr "" msgid "Please enter a unique name for this App Password or use our randomly generated one." msgstr "" +#: src/components/dialogs/MutedWords.tsx:68 +msgid "Please enter a valid word, tag, or phrase to mute" +msgstr "" + #: src/view/com/auth/create/state.ts:170 #~ msgid "Please enter the code you received by SMS." #~ msgstr "" @@ -2949,13 +2991,13 @@ msgstr "" msgid "Post by {0}" msgstr "" -#: src/Navigation.tsx:172 -#: src/Navigation.tsx:179 -#: src/Navigation.tsx:186 +#: src/Navigation.tsx:174 +#: src/Navigation.tsx:181 +#: src/Navigation.tsx:188 msgid "Post by @{0}" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:90 +#: src/view/com/util/forms/PostDropdownBtn.tsx:108 msgid "Post deleted" msgstr "" @@ -2975,7 +3017,7 @@ msgstr "" msgid "Post not found" msgstr "" -#: src/components/TagMenu/index.tsx:257 +#: src/components/TagMenu/index.tsx:253 msgid "posts" msgstr "" @@ -2983,7 +3025,7 @@ msgstr "" msgid "Posts" msgstr "" -#: src/components/dialogs/MutedWords.tsx:77 +#: src/components/dialogs/MutedWords.tsx:90 msgid "Posts can be muted based on their text, their tags, or both." msgstr "" @@ -3012,7 +3054,7 @@ msgstr "" msgid "Privacy" msgstr "" -#: src/Navigation.tsx:217 +#: src/Navigation.tsx:219 #: src/view/screens/PrivacyPolicy.tsx:29 #: src/view/screens/Settings/index.tsx:891 #: src/view/shell/Drawer.tsx:262 @@ -3089,7 +3131,7 @@ msgstr "" msgid "Recommended Users" msgstr "" -#: src/components/dialogs/MutedWords.tsx:249 +#: src/components/dialogs/MutedWords.tsx:298 #: src/view/com/modals/ListAddRemoveUsers.tsx:264 #: src/view/com/modals/SelfLabel.tsx:83 #: src/view/com/modals/UserAddRemoveLists.tsx:219 @@ -3127,7 +3169,7 @@ msgstr "" msgid "Remove image preview" msgstr "" -#: src/components/dialogs/MutedWords.tsx:294 +#: src/components/dialogs/MutedWords.tsx:343 msgid "Remove mute word from your list" msgstr "" @@ -3197,7 +3239,8 @@ msgid "Report List" msgstr "" #: src/view/com/modals/report/SendReportButton.tsx:37 -#: src/view/com/util/forms/PostDropdownBtn.tsx:255 +#: src/view/com/util/forms/PostDropdownBtn.tsx:301 +#: src/view/com/util/forms/PostDropdownBtn.tsx:309 msgid "Report post" msgstr "" @@ -3256,7 +3299,7 @@ msgstr "" msgid "Require alt text before posting" msgstr "" -#: src/view/com/auth/create/Step1.tsx:153 +#: src/view/com/auth/create/Step1.tsx:146 msgid "Required for this provider" msgstr "" @@ -3321,7 +3364,7 @@ msgstr "" #~ msgid "Retry." #~ msgstr "" -#: src/view/screens/ProfileList.tsx:898 +#: src/view/screens/ProfileList.tsx:903 msgid "Return to previous page" msgstr "" @@ -3376,11 +3419,11 @@ msgstr "" msgid "Science" msgstr "" -#: src/view/screens/ProfileList.tsx:854 +#: src/view/screens/ProfileList.tsx:859 msgid "Scroll to top" msgstr "" -#: src/Navigation.tsx:440 +#: src/Navigation.tsx:447 #: src/view/com/auth/LoggedOut.tsx:122 #: src/view/com/modals/ListAddRemoveUsers.tsx:75 #: src/view/com/util/forms/SearchInput.tsx:67 @@ -3403,13 +3446,21 @@ msgid "Search for \"{query}\"" msgstr "" #: src/components/TagMenu/index.tsx:145 -msgid "Search for all posts by @{authorHandle} with tag {tag}" +msgid "Search for all posts by @{authorHandle} with tag {displayTag}" msgstr "" -#: src/components/TagMenu/index.tsx:90 -msgid "Search for all posts with tag {tag}" +#: src/components/TagMenu/index.tsx:145 +#~ msgid "Search for all posts by @{authorHandle} with tag {tag}" +#~ msgstr "" + +#: src/components/TagMenu/index.tsx:94 +msgid "Search for all posts with tag {displayTag}" msgstr "" +#: src/components/TagMenu/index.tsx:90 +#~ msgid "Search for all posts with tag {tag}" +#~ msgstr "" + #: src/view/com/auth/LoggedOut.tsx:104 #: src/view/com/auth/LoggedOut.tsx:105 #: src/view/com/modals/ListAddRemoveUsers.tsx:70 @@ -3420,22 +3471,30 @@ msgstr "" msgid "Security Step Required" msgstr "" -#: src/components/TagMenu/index.web.tsx:50 +#: src/components/TagMenu/index.web.tsx:66 msgid "See {truncatedTag} posts" msgstr "" -#: src/components/TagMenu/index.web.tsx:67 +#: src/components/TagMenu/index.web.tsx:83 msgid "See {truncatedTag} posts by user" msgstr "" #: src/components/TagMenu/index.tsx:128 -msgid "See <0>{tag}</0> posts" +msgid "See <0>{displayTag}</0> posts" msgstr "" -#: src/components/TagMenu/index.tsx:189 -msgid "See <0>{tag}</0> posts by this user" +#: src/components/TagMenu/index.tsx:187 +msgid "See <0>{displayTag}</0> posts by this user" msgstr "" +#: src/components/TagMenu/index.tsx:128 +#~ msgid "See <0>{tag}</0> posts" +#~ msgstr "" + +#: src/components/TagMenu/index.tsx:189 +#~ msgid "See <0>{tag}</0> posts by this user" +#~ msgstr "" + #: src/view/screens/SavedFeeds.tsx:163 msgid "See this guide" msgstr "" @@ -3460,7 +3519,7 @@ msgstr "" msgid "Select option {i} of {numItems}" msgstr "" -#: src/view/com/auth/create/Step1.tsx:103 +#: src/view/com/auth/create/Step1.tsx:96 #: src/view/com/auth/login/LoginForm.tsx:150 msgid "Select service" msgstr "" @@ -3578,7 +3637,7 @@ msgstr "" msgid "Set new password" msgstr "" -#: src/view/com/auth/create/Step1.tsx:225 +#: src/view/com/auth/create/Step1.tsx:202 msgid "Set password" msgstr "" @@ -3622,12 +3681,12 @@ msgstr "" msgid "Sets hosting provider for password reset" msgstr "" -#: src/view/com/auth/create/Step1.tsx:104 +#: src/view/com/auth/create/Step1.tsx:97 #: src/view/com/auth/login/LoginForm.tsx:151 msgid "Sets server for the Bluesky client" msgstr "" -#: src/Navigation.tsx:135 +#: src/Navigation.tsx:137 #: src/view/screens/Settings/index.tsx:294 #: src/view/shell/desktop/LeftNav.tsx:433 #: src/view/shell/Drawer.tsx:567 @@ -3645,7 +3704,9 @@ msgid "Share" msgstr "" #: src/view/com/profile/ProfileHeader.tsx:295 -#: src/view/com/util/forms/PostDropdownBtn.tsx:184 +#: src/view/com/util/forms/PostDropdownBtn.tsx:231 +#: src/view/com/util/forms/PostDropdownBtn.tsx:237 +#: src/view/com/util/post-ctrls/PostCtrls.tsx:215 #: src/view/screens/ProfileList.tsx:418 msgid "Share" msgstr "" @@ -3737,7 +3798,7 @@ msgstr "" msgid "Show the content" msgstr "" -#: src/view/com/notifications/FeedItem.tsx:346 +#: src/view/com/notifications/FeedItem.tsx:347 msgid "Show users" msgstr "" @@ -3844,11 +3905,15 @@ msgstr "" #~ msgid "Something went wrong and we're not sure what." #~ msgstr "" -#: src/view/com/modals/Waitlist.tsx:51 -msgid "Something went wrong. Check your email and try again." +#: src/components/Lists.tsx:203 +msgid "Something went wrong!" msgstr "" -#: src/App.native.tsx:63 +#: src/view/com/modals/Waitlist.tsx:51 +#~ msgid "Something went wrong. Check your email and try again." +#~ msgstr "" + +#: src/App.native.tsx:66 msgid "Sorry! Your session expired. Please log in again." msgstr "" @@ -3884,7 +3949,7 @@ msgstr "" msgid "Storage cleared, you need to restart the app now." msgstr "" -#: src/Navigation.tsx:202 +#: src/Navigation.tsx:204 #: src/view/screens/Settings/index.tsx:807 msgid "Storybook" msgstr "" @@ -3898,7 +3963,7 @@ msgid "Subscribe" msgstr "" #: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:173 -#: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:307 +#: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:308 msgid "Subscribe to the {0} feed" msgstr "" @@ -3918,7 +3983,7 @@ msgstr "" msgid "Suggestive" msgstr "" -#: src/Navigation.tsx:212 +#: src/Navigation.tsx:214 #: src/view/screens/Support.tsx:30 #: src/view/screens/Support.tsx:33 msgid "Support" @@ -3950,14 +4015,18 @@ msgstr "" msgid "System log" msgstr "" -#: src/components/dialogs/MutedWords.tsx:288 +#: src/components/dialogs/MutedWords.tsx:337 msgid "tag" msgstr "" -#: src/components/TagMenu/index.tsx:74 -msgid "Tag menu: {tag}" +#: src/components/TagMenu/index.tsx:78 +msgid "Tag menu: {displayTag}" msgstr "" +#: src/components/TagMenu/index.tsx:74 +#~ msgid "Tag menu: {tag}" +#~ msgstr "" + #: src/view/com/modals/crop-image/CropImage.web.tsx:112 msgid "Tall" msgstr "" @@ -3974,14 +4043,14 @@ msgstr "" msgid "Terms" msgstr "" -#: src/Navigation.tsx:222 +#: src/Navigation.tsx:224 #: src/view/screens/Settings/index.tsx:885 #: src/view/screens/TermsOfService.tsx:29 #: src/view/shell/Drawer.tsx:256 msgid "Terms of Service" msgstr "" -#: src/components/dialogs/MutedWords.tsx:288 +#: src/components/dialogs/MutedWords.tsx:337 msgid "text" msgstr "" @@ -4062,7 +4131,7 @@ msgstr "" msgid "There was an issue fetching notifications. Tap here to try again." msgstr "" -#: src/view/com/posts/Feed.tsx:263 +#: src/view/com/posts/Feed.tsx:265 msgid "There was an issue fetching posts. Tap here to try again." msgstr "" @@ -4168,7 +4237,7 @@ msgstr "" msgid "This link is taking you to the following website:" msgstr "" -#: src/view/screens/ProfileList.tsx:834 +#: src/view/screens/ProfileList.tsx:839 msgid "This list is empty!" msgstr "" @@ -4200,11 +4269,11 @@ msgstr "" msgid "This warning is only available for posts with media attached." msgstr "" -#: src/components/dialogs/MutedWords.tsx:236 +#: src/components/dialogs/MutedWords.tsx:285 msgid "This will delete {0} from your muted words. You can always add it back later." msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:237 +#: src/view/com/util/forms/PostDropdownBtn.tsx:282 msgid "This will hide this post from your feeds." msgstr "" @@ -4217,11 +4286,11 @@ msgstr "" msgid "Threaded Mode" msgstr "" -#: src/Navigation.tsx:255 +#: src/Navigation.tsx:257 msgid "Threads Preferences" msgstr "" -#: src/components/dialogs/MutedWords.tsx:95 +#: src/components/dialogs/MutedWords.tsx:113 msgid "Toggle between muted word options." msgstr "" @@ -4235,7 +4304,8 @@ msgstr "" #: src/view/com/post-thread/PostThreadItem.tsx:685 #: src/view/com/post-thread/PostThreadItem.tsx:687 -#: src/view/com/util/forms/PostDropdownBtn.tsx:156 +#: src/view/com/util/forms/PostDropdownBtn.tsx:215 +#: src/view/com/util/forms/PostDropdownBtn.tsx:217 msgid "Translate" msgstr "" @@ -4296,16 +4366,15 @@ msgid "Unfortunately, you do not meet the requirements to create an account." msgstr "" #: src/view/com/util/post-ctrls/PostCtrls.tsx:182 -#: src/view/com/util/post-ctrls/PostCtrls.tsx:216 msgid "Unlike" msgstr "" -#: src/components/TagMenu/index.tsx:253 +#: src/components/TagMenu/index.tsx:249 #: src/view/screens/ProfileList.tsx:597 msgid "Unmute" msgstr "" -#: src/components/TagMenu/index.web.tsx:90 +#: src/components/TagMenu/index.web.tsx:104 msgid "Unmute {truncatedTag}" msgstr "" @@ -4313,11 +4382,16 @@ msgstr "" msgid "Unmute Account" msgstr "" -#: src/components/TagMenu/index.tsx:210 -msgid "Unmute all {tag} posts" +#: src/components/TagMenu/index.tsx:208 +msgid "Unmute all {displayTag} posts" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:202 +#: src/components/TagMenu/index.tsx:210 +#~ msgid "Unmute all {tag} posts" +#~ msgstr "" + +#: src/view/com/util/forms/PostDropdownBtn.tsx:251 +#: src/view/com/util/forms/PostDropdownBtn.tsx:256 msgid "Unmute thread" msgstr "" @@ -4401,13 +4475,13 @@ msgstr "" msgid "User list by {0}" msgstr "" -#: src/view/screens/ProfileList.tsx:762 +#: src/view/screens/ProfileList.tsx:763 msgid "User list by <0/>" msgstr "" #: src/view/com/lists/ListCard.tsx:83 #: src/view/com/modals/UserAddRemoveLists.tsx:196 -#: src/view/screens/ProfileList.tsx:760 +#: src/view/screens/ProfileList.tsx:761 msgid "User list by you" msgstr "" @@ -4428,7 +4502,7 @@ msgstr "" msgid "Username or email address" msgstr "" -#: src/view/screens/ProfileList.tsx:796 +#: src/view/screens/ProfileList.tsx:797 msgid "Users" msgstr "" @@ -4502,6 +4576,10 @@ msgstr "" msgid "We also think you'll like \"For You\" by Skygaze:" msgstr "" +#: src/screens/Hashtag.tsx:132 +msgid "We couldn't find any results for that hashtag." +msgstr "" + #: src/screens/Deactivated.tsx:133 msgid "We estimate {estimatedTime} until your account is ready." msgstr "" @@ -4518,7 +4596,7 @@ msgstr "" #~ msgid "We recommend \"For You\" by Skygaze:" #~ msgstr "" -#: src/components/dialogs/MutedWords.tsx:161 +#: src/components/dialogs/MutedWords.tsx:204 msgid "We recommend avoiding common words that appear in many posts, since it can result in no posts being shown." msgstr "" @@ -4550,7 +4628,7 @@ msgstr "" msgid "We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @{handleOrDid}." msgstr "" -#: src/components/dialogs/MutedWords.tsx:182 +#: src/components/dialogs/MutedWords.tsx:230 msgid "We're sorry, but we weren't able to load your muted words at this time. Please try again." msgstr "" @@ -4558,6 +4636,7 @@ msgstr "" msgid "We're sorry, but your search could not be completed. Please try again in a few minutes." msgstr "" +#: src/components/Lists.tsx:211 #: src/view/screens/NotFound.tsx:48 msgid "We're sorry! We can't find the page you were looking for." msgstr "" @@ -4705,7 +4784,7 @@ msgstr "" msgid "You have not muted any accounts yet. To mute an account, go to their profile and selected \"Mute account\" from the menu on their account." msgstr "" -#: src/components/dialogs/MutedWords.tsx:202 +#: src/components/dialogs/MutedWords.tsx:250 msgid "You haven't muted any words or tags yet" msgstr "" @@ -4717,11 +4796,11 @@ msgstr "" msgid "You must be 18 years or older to enable adult content" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:129 +#: src/view/com/util/forms/PostDropdownBtn.tsx:147 msgid "You will no longer receive notifications for this thread" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:132 +#: src/view/com/util/forms/PostDropdownBtn.tsx:150 msgid "You will now receive notifications for this thread" msgstr "" @@ -4747,7 +4826,7 @@ msgstr "" msgid "You've reached the end of your feed! Find some more accounts to follow." msgstr "" -#: src/view/com/auth/create/Step1.tsx:74 +#: src/view/com/auth/create/Step1.tsx:67 msgid "Your account" msgstr "" @@ -4759,7 +4838,7 @@ msgstr "" msgid "Your account repository, containing all public data records, can be downloaded as a \"CAR\" file. This file does not include media embeds, such as images, or your private data, which must be fetched separately." msgstr "" -#: src/view/com/auth/create/Step1.tsx:238 +#: src/view/com/auth/create/Step1.tsx:215 msgid "Your birth date" msgstr "" @@ -4778,8 +4857,8 @@ msgid "Your email appears to be invalid." msgstr "" #: src/view/com/modals/Waitlist.tsx:109 -msgid "Your email has been saved! We'll be in touch soon." -msgstr "" +#~ msgid "Your email has been saved! We'll be in touch soon." +#~ msgstr "" #: src/view/com/modals/ChangeEmail.tsx:125 msgid "Your email has been updated but not verified. As a next step, please verify your new email." @@ -4807,7 +4886,7 @@ msgstr "" #~ msgid "Your invite codes are hidden when logged in using an App Password" #~ msgstr "" -#: src/components/dialogs/MutedWords.tsx:173 +#: src/components/dialogs/MutedWords.tsx:221 msgid "Your muted words" msgstr "" diff --git a/src/locale/locales/es/messages.po b/src/locale/locales/es/messages.po index fed1beb6c..1c7344809 100644 --- a/src/locale/locales/es/messages.po +++ b/src/locale/locales/es/messages.po @@ -75,12 +75,12 @@ msgstr "Se ha aplicado una advertencia de contenido a este {0}." msgid "A new version of the app is available. Please update to continue using the app." msgstr "Ya está disponible una nueva versión de la aplicación. ActualÃzala para seguir utilizándola." -#: src/view/com/util/ViewHeader.tsx:83 +#: src/view/com/util/ViewHeader.tsx:89 #: src/view/screens/Search/Search.tsx:647 msgid "Access navigation links and settings" msgstr "" -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:51 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:52 msgid "Access profile and other navigation links" msgstr "" @@ -127,11 +127,11 @@ msgstr "" msgid "Account unmuted" msgstr "" -#: src/components/dialogs/MutedWords.tsx:147 +#: src/components/dialogs/MutedWords.tsx:165 #: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:150 #: src/view/com/modals/ListAddRemoveUsers.tsx:264 #: src/view/com/modals/UserAddRemoveLists.tsx:219 -#: src/view/screens/ProfileList.tsx:812 +#: src/view/screens/ProfileList.tsx:813 msgid "Add" msgstr "Agregar" @@ -139,7 +139,7 @@ msgstr "Agregar" msgid "Add a content warning" msgstr "Agregar una advertencia de cuenta" -#: src/view/screens/ProfileList.tsx:802 +#: src/view/screens/ProfileList.tsx:803 msgid "Add a user to this list" msgstr "Agregar un usuario a esta lista" @@ -177,11 +177,11 @@ msgstr "Agregar una tarjeta de enlace" msgid "Add link card:" msgstr "Agregar una tarjeta de enlace:" -#: src/components/dialogs/MutedWords.tsx:140 +#: src/components/dialogs/MutedWords.tsx:158 msgid "Add mute word for configured settings" msgstr "" -#: src/components/dialogs/MutedWords.tsx:74 +#: src/components/dialogs/MutedWords.tsx:87 msgid "Add muted words and tags" msgstr "" @@ -269,7 +269,7 @@ msgstr "Se ha enviado un correo electrónico a tu dirección previa, {0}. Incluy msgid "An issue occurred, please try again." msgstr "" -#: src/view/com/notifications/FeedItem.tsx:236 +#: src/view/com/notifications/FeedItem.tsx:237 #: src/view/com/threadgate/WhoCanReply.tsx:178 msgid "and" msgstr "y" @@ -302,13 +302,14 @@ msgstr "" #~ msgid "App passwords" #~ msgstr "Contraseñas de la app" -#: src/Navigation.tsx:237 +#: src/Navigation.tsx:239 #: src/view/screens/AppPasswords.tsx:187 #: src/view/screens/Settings/index.tsx:684 msgid "App Passwords" msgstr "Contraseñas de la app" -#: src/view/com/util/forms/PostDropdownBtn.tsx:295 +#: src/view/com/util/forms/PostDropdownBtn.tsx:337 +#: src/view/com/util/forms/PostDropdownBtn.tsx:346 msgid "Appeal content warning" msgstr "Aviso sobre el contenido del recurso" @@ -336,12 +337,12 @@ msgstr "¿Estás seguro de que quieres eliminar la contraseña de la app \"{name msgid "Are you sure you'd like to discard this draft?" msgstr "¿Estás seguro de que quieres descartar este borrador?" -#: src/components/dialogs/MutedWords.tsx:233 +#: src/components/dialogs/MutedWords.tsx:282 #: src/view/screens/ProfileList.tsx:365 msgid "Are you sure?" msgstr "¿Estás seguro?" -#: src/view/com/util/forms/PostDropdownBtn.tsx:278 +#: src/view/com/util/forms/PostDropdownBtn.tsx:322 msgid "Are you sure? This cannot be undone." msgstr "¿Estás seguro? Esto no puede deshacerse." @@ -367,7 +368,7 @@ msgstr "Desnudez artÃstica o no erótica." #: src/view/com/post-thread/PostThread.tsx:522 #: src/view/com/post-thread/PostThread.tsx:530 #: src/view/com/profile/ProfileHeader.tsx:649 -#: src/view/com/util/ViewHeader.tsx:81 +#: src/view/com/util/ViewHeader.tsx:87 msgid "Back" msgstr "Regresar" @@ -384,7 +385,7 @@ msgstr "" msgid "Basics" msgstr "Conceptos básicos" -#: src/view/com/auth/create/Step1.tsx:250 +#: src/view/com/auth/create/Step1.tsx:227 #: src/view/com/modals/BirthDateSettings.tsx:73 msgid "Birthday" msgstr "Cumpleaños" @@ -423,7 +424,7 @@ msgstr "" msgid "Blocked accounts" msgstr "Cuentas bloqueadas" -#: src/Navigation.tsx:130 +#: src/Navigation.tsx:132 #: src/view/screens/ModerationBlockedAccounts.tsx:107 msgid "Blocked Accounts" msgstr "Cuentas bloqueadas" @@ -475,8 +476,8 @@ msgid "Bluesky is public." msgstr "Bluesky es público." #: src/view/com/modals/Waitlist.tsx:70 -msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon." -msgstr "Bluesky utiliza las invitaciones para construir una comunidad más saludable. Si no conoces a nadie con una invitación, puedes apuntarte a la lista de espera y te enviaremos una en breve." +#~ msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon." +#~ msgstr "Bluesky utiliza las invitaciones para construir una comunidad más saludable. Si no conoces a nadie con una invitación, puedes apuntarte a la lista de espera y te enviaremos una en breve." #: src/view/screens/Moderation.tsx:245 msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private." @@ -529,7 +530,7 @@ msgstr "Cámara" msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must be at least 4 characters long, but no more than 32 characters long." msgstr "Sólo puede contener letras, números, espacios, guiones y guiones bajos. Debe tener al menos 4 caracteres, pero no más de 32." -#: src/components/Prompt.tsx:91 +#: src/components/Prompt.tsx:101 #: src/view/com/composer/Composer.tsx:307 #: src/view/com/composer/Composer.tsx:312 #: src/view/com/modals/ChangeEmail.tsx:218 @@ -544,7 +545,6 @@ msgstr "Sólo puede contener letras, números, espacios, guiones y guiones bajos #: src/view/com/modals/Repost.tsx:87 #: src/view/com/modals/VerifyEmail.tsx:247 #: src/view/com/modals/VerifyEmail.tsx:253 -#: src/view/com/modals/Waitlist.tsx:142 #: src/view/screens/Search/Search.tsx:716 #: src/view/shell/desktop/Search.tsx:238 msgid "Cancel" @@ -586,8 +586,8 @@ msgid "Cancel search" msgstr "Cancelar búsqueda" #: src/view/com/modals/Waitlist.tsx:136 -msgid "Cancel waitlist signup" -msgstr "Cancelar la inscripción en la lista de espera" +#~ msgid "Cancel waitlist signup" +#~ msgstr "Cancelar la inscripción en la lista de espera" #: src/view/screens/Settings/index.tsx:334 msgctxt "action" @@ -673,7 +673,7 @@ msgstr "Elige los algoritmos que potencian tu experiencia con publicaciones pers msgid "Choose your main feeds" msgstr "" -#: src/view/com/auth/create/Step1.tsx:219 +#: src/view/com/auth/create/Step1.tsx:196 msgid "Choose your password" msgstr "Elige tu contraseña" @@ -704,11 +704,14 @@ msgstr "Borrar consulta de búsqueda" msgid "click here" msgstr "" -#: src/components/RichText.tsx:189 -#: src/components/TagMenu/index.web.tsx:125 +#: src/components/TagMenu/index.web.tsx:138 msgid "Click here to open tag menu for {tag}" msgstr "" +#: src/components/RichText.tsx:191 +msgid "Click here to open tag menu for #{tag}" +msgstr "" + #: src/screens/Onboarding/index.tsx:35 msgid "Climate" msgstr "" @@ -718,8 +721,8 @@ msgstr "" msgid "Close" msgstr "" -#: src/components/Dialog/index.web.tsx:80 -#: src/components/Dialog/index.web.tsx:194 +#: src/components/Dialog/index.web.tsx:84 +#: src/components/Dialog/index.web.tsx:198 msgid "Close active dialog" msgstr "" @@ -743,7 +746,7 @@ msgstr "Cerrar el visor de imagen" msgid "Close navigation footer" msgstr "Cerrar el pie de página de navegación" -#: src/components/TagMenu/index.tsx:266 +#: src/components/TagMenu/index.tsx:262 msgid "Close this dialog" msgstr "" @@ -763,7 +766,7 @@ msgstr "" msgid "Closes viewer for header image" msgstr "" -#: src/view/com/notifications/FeedItem.tsx:317 +#: src/view/com/notifications/FeedItem.tsx:318 msgid "Collapses list of users for a given notification" msgstr "" @@ -775,7 +778,7 @@ msgstr "" msgid "Comics" msgstr "" -#: src/Navigation.tsx:227 +#: src/Navigation.tsx:229 #: src/view/screens/CommunityGuidelines.tsx:32 msgid "Community Guidelines" msgstr "Directrices de la comunidad" @@ -800,7 +803,7 @@ msgstr "Redactar la respuesta" msgid "Configure content filtering setting for category: {0}" msgstr "" -#: src/components/Prompt.tsx:113 +#: src/components/Prompt.tsx:124 #: src/view/com/modals/AppealLabel.tsx:98 #: src/view/com/modals/SelfLabel.tsx:154 #: src/view/com/modals/VerifyEmail.tsx:231 @@ -840,8 +843,8 @@ msgid "Confirmation code" msgstr "Código de confirmación" #: src/view/com/modals/Waitlist.tsx:120 -msgid "Confirms signing up {email} to the waitlist" -msgstr "" +#~ msgid "Confirms signing up {email} to the waitlist" +#~ msgstr "" #: src/view/com/auth/create/CreateAccount.tsx:193 #: src/view/com/auth/login/LoginForm.tsx:278 @@ -918,7 +921,7 @@ msgstr "" #: src/view/com/modals/AddAppPasswords.tsx:76 #: src/view/com/modals/InviteCodes.tsx:152 -#: src/view/com/util/forms/PostDropdownBtn.tsx:143 +#: src/view/com/util/forms/PostDropdownBtn.tsx:161 msgid "Copied to clipboard" msgstr "" @@ -934,7 +937,8 @@ msgstr "Copiar" msgid "Copy link to list" msgstr "Copia el enlace a la lista" -#: src/view/com/util/forms/PostDropdownBtn.tsx:184 +#: src/view/com/util/forms/PostDropdownBtn.tsx:231 +#: src/view/com/util/forms/PostDropdownBtn.tsx:237 msgid "Copy link to post" msgstr "Copia el enlace a la publicación" @@ -942,11 +946,12 @@ msgstr "Copia el enlace a la publicación" msgid "Copy link to profile" msgstr "Copia el enlace al perfil" -#: src/view/com/util/forms/PostDropdownBtn.tsx:170 +#: src/view/com/util/forms/PostDropdownBtn.tsx:223 +#: src/view/com/util/forms/PostDropdownBtn.tsx:225 msgid "Copy post text" msgstr "Copiar el texto de la publicación" -#: src/Navigation.tsx:232 +#: src/Navigation.tsx:234 #: src/view/screens/CopyrightPolicy.tsx:29 msgid "Copyright Policy" msgstr "PolÃtica de derechos de autor" @@ -955,7 +960,7 @@ msgstr "PolÃtica de derechos de autor" msgid "Could not load feed" msgstr "No se ha podido cargar las publicaciones" -#: src/view/screens/ProfileList.tsx:888 +#: src/view/screens/ProfileList.tsx:893 msgid "Could not load list" msgstr "No se ha podido cargar la lista" @@ -1075,11 +1080,12 @@ msgstr "Borrar mi cuenta" msgid "Delete My Account…" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:273 +#: src/view/com/util/forms/PostDropdownBtn.tsx:317 +#: src/view/com/util/forms/PostDropdownBtn.tsx:326 msgid "Delete post" msgstr "Borrar una publicación" -#: src/view/com/util/forms/PostDropdownBtn.tsx:277 +#: src/view/com/util/forms/PostDropdownBtn.tsx:321 msgid "Delete this post?" msgstr "¿Borrar esta publicación?" @@ -1148,8 +1154,8 @@ msgid "Domain verified!" msgstr "¡Dominio verificado!" #: src/view/com/auth/create/Step1.tsx:170 -msgid "Don't have an invite code?" -msgstr "" +#~ msgid "Don't have an invite code?" +#~ msgstr "" #: src/view/com/auth/onboarding/RecommendedFollows.tsx:86 #: src/view/com/modals/EditImage.tsx:333 @@ -1251,7 +1257,7 @@ msgstr "Editar los detalles de la lista" msgid "Edit Moderation List" msgstr "" -#: src/Navigation.tsx:242 +#: src/Navigation.tsx:244 #: src/view/screens/Feeds.tsx:434 #: src/view/screens/SavedFeeds.tsx:84 msgid "Edit My Feeds" @@ -1269,7 +1275,7 @@ msgstr "Editar el perfil" msgid "Edit Profile" msgstr "Editar el perfil" -#: src/view/com/home/HomeHeaderLayout.web.tsx:59 +#: src/view/com/home/HomeHeaderLayout.web.tsx:62 #: src/view/screens/Feeds.tsx:355 msgid "Edit Saved Feeds" msgstr "Editar mis noticias guardadas" @@ -1290,14 +1296,13 @@ msgstr "" msgid "Education" msgstr "" -#: src/view/com/auth/create/Step1.tsx:199 +#: src/view/com/auth/create/Step1.tsx:176 #: src/view/com/auth/login/ForgotPasswordForm.tsx:156 #: src/view/com/modals/ChangeEmail.tsx:141 -#: src/view/com/modals/Waitlist.tsx:88 msgid "Email" msgstr "Correo electrónico" -#: src/view/com/auth/create/Step1.tsx:190 +#: src/view/com/auth/create/Step1.tsx:167 #: src/view/com/auth/login/ForgotPasswordForm.tsx:147 msgid "Email address" msgstr "Dirección de correo electrónico" @@ -1352,8 +1357,8 @@ msgstr "Fin de noticias" msgid "Enter a name for this App Password" msgstr "" -#: src/components/dialogs/MutedWords.tsx:87 -#: src/components/dialogs/MutedWords.tsx:88 +#: src/components/dialogs/MutedWords.tsx:100 +#: src/components/dialogs/MutedWords.tsx:101 msgid "Enter a word or tag" msgstr "" @@ -1373,16 +1378,16 @@ msgstr "Introduce el dominio que quieres utilizar" msgid "Enter the email you used to create your account. We'll send you a \"reset code\" so you can set a new password." msgstr "Introduce el correo electrónico que utilizaste para crear tu cuenta. Te enviaremos un \"código de restablecimiento\" para que puedas establecer una nueva contraseña." -#: src/view/com/auth/create/Step1.tsx:251 +#: src/view/com/auth/create/Step1.tsx:228 #: src/view/com/modals/BirthDateSettings.tsx:74 msgid "Enter your birth date" msgstr "" #: src/view/com/modals/Waitlist.tsx:78 -msgid "Enter your email" -msgstr "" +#~ msgid "Enter your email" +#~ msgstr "" -#: src/view/com/auth/create/Step1.tsx:195 +#: src/view/com/auth/create/Step1.tsx:172 msgid "Enter your email address" msgstr "Introduce la dirección de correo electrónico" @@ -1428,8 +1433,8 @@ msgid "Exits inputting search query" msgstr "" #: src/view/com/modals/Waitlist.tsx:138 -msgid "Exits signing up for waitlist with {email}" -msgstr "" +#~ msgid "Exits signing up for waitlist with {email}" +#~ msgstr "" #: src/view/com/lightbox/Lightbox.web.tsx:163 msgid "Expand alt text" @@ -1458,7 +1463,7 @@ msgstr "" msgid "External media may allow websites to collect information about you and your device. No information is sent or requested until you press the \"play\" button." msgstr "" -#: src/Navigation.tsx:261 +#: src/Navigation.tsx:263 #: src/view/screens/PreferencesExternalEmbeds.tsx:52 #: src/view/screens/Settings/index.tsx:657 msgid "External Media Preferences" @@ -1477,7 +1482,7 @@ msgstr "" msgid "Failed to create the list. Check your internet connection and try again." msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:110 +#: src/view/com/util/forms/PostDropdownBtn.tsx:128 msgid "Failed to delete post, please try again" msgstr "" @@ -1486,7 +1491,7 @@ msgstr "" msgid "Failed to load recommended feeds" msgstr "Error al cargar las noticias recomendadas" -#: src/Navigation.tsx:192 +#: src/Navigation.tsx:194 msgid "Feed" msgstr "" @@ -1507,7 +1512,7 @@ msgstr "Noticias fuera de lÃnea" msgid "Feedback" msgstr "Comentarios" -#: src/Navigation.tsx:445 +#: src/Navigation.tsx:452 #: src/view/screens/Feeds.tsx:419 #: src/view/screens/Feeds.tsx:524 #: src/view/screens/Profile.tsx:184 @@ -1648,9 +1653,9 @@ msgstr "Siguiendo" msgid "Following {0}" msgstr "" -#: src/Navigation.tsx:248 -#: src/view/com/home/HomeHeaderLayout.web.tsx:45 -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:83 +#: src/Navigation.tsx:250 +#: src/view/com/home/HomeHeaderLayout.web.tsx:50 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:84 #: src/view/screens/PreferencesFollowingFeed.tsx:104 #: src/view/screens/Settings/index.tsx:543 msgid "Following Feed Preferences" @@ -1689,6 +1694,11 @@ msgstr "Olvidé mi contraseña" msgid "Forgot Password" msgstr "Olvidé mi contraseña" +#: src/screens/Hashtag.tsx:108 +#: src/screens/Hashtag.tsx:148 +msgid "From @{sanitizedAuthor}" +msgstr "" + #: src/view/com/posts/FeedItem.tsx:189 msgctxt "from-feed" msgid "From <0/>" @@ -1712,8 +1722,8 @@ msgstr "Regresar" #: src/view/screens/ProfileFeed.tsx:106 #: src/view/screens/ProfileFeed.tsx:111 -#: src/view/screens/ProfileList.tsx:897 #: src/view/screens/ProfileList.tsx:902 +#: src/view/screens/ProfileList.tsx:907 msgid "Go Back" msgstr "Regresar" @@ -1739,8 +1749,16 @@ msgstr "Ir al siguiente" msgid "Handle" msgstr "Identificador" +#: src/Navigation.tsx:270 +msgid "Hashtag" +msgstr "" + #: src/components/RichText.tsx:188 -msgid "Hashtag: {tag}" +#~ msgid "Hashtag: {tag}" +#~ msgstr "" + +#: src/components/RichText.tsx:190 +msgid "Hashtag: #{tag}" msgstr "" #: src/view/com/auth/create/CreateAccount.tsx:208 @@ -1776,12 +1794,13 @@ msgid "Hide" msgstr "Ocultar" #: src/view/com/modals/ContentFilteringSettings.tsx:224 -#: src/view/com/notifications/FeedItem.tsx:325 +#: src/view/com/notifications/FeedItem.tsx:326 msgctxt "action" msgid "Hide" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:232 +#: src/view/com/util/forms/PostDropdownBtn.tsx:276 +#: src/view/com/util/forms/PostDropdownBtn.tsx:287 msgid "Hide post" msgstr "Ocultar publicación" @@ -1790,11 +1809,11 @@ msgstr "Ocultar publicación" msgid "Hide the content" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:236 +#: src/view/com/util/forms/PostDropdownBtn.tsx:280 msgid "Hide this post?" msgstr "¿Ocultar esta publicación?" -#: src/view/com/notifications/FeedItem.tsx:315 +#: src/view/com/notifications/FeedItem.tsx:316 msgid "Hide user list" msgstr "Ocultar la lista de usuarios" @@ -1822,7 +1841,7 @@ msgstr "El servidor de noticias ha respondido de forma incorrecta. Por favor, in msgid "Hmm, we're having trouble finding this feed. It may have been deleted." msgstr "Tenemos problemas para encontrar esta noticia. Puede que la hayan borrado." -#: src/Navigation.tsx:435 +#: src/Navigation.tsx:442 #: src/view/shell/bottom-bar/BottomBar.tsx:137 #: src/view/shell/desktop/LeftNav.tsx:306 #: src/view/shell/Drawer.tsx:398 @@ -1837,7 +1856,7 @@ msgstr "Página inicial" #~ msgid "Home Feed Preferences" #~ msgstr "Preferencias de noticias de la página inicial" -#: src/view/com/auth/create/Step1.tsx:82 +#: src/view/com/auth/create/Step1.tsx:75 #: src/view/com/auth/login/ForgotPasswordForm.tsx:120 msgid "Hosting provider" msgstr "Proveedor de alojamiento" @@ -1891,11 +1910,11 @@ msgstr "" msgid "Input confirmation code for account deletion" msgstr "" -#: src/view/com/auth/create/Step1.tsx:200 +#: src/view/com/auth/create/Step1.tsx:177 msgid "Input email for Bluesky account" msgstr "" -#: src/view/com/auth/create/Step1.tsx:158 +#: src/view/com/auth/create/Step1.tsx:151 msgid "Input invite code to proceed" msgstr "" @@ -1928,8 +1947,8 @@ msgstr "" #~ msgstr "" #: src/view/com/modals/Waitlist.tsx:90 -msgid "Input your email to get on the Bluesky waitlist" -msgstr "" +#~ msgid "Input your email to get on the Bluesky waitlist" +#~ msgstr "" #: src/view/com/auth/login/LoginForm.tsx:229 msgid "Input your password" @@ -1955,8 +1974,8 @@ msgstr "Nombre de usuario o contraseña no válidos" msgid "Invite a Friend" msgstr "Invitar a un amigo" -#: src/view/com/auth/create/Step1.tsx:148 -#: src/view/com/auth/create/Step1.tsx:157 +#: src/view/com/auth/create/Step1.tsx:141 +#: src/view/com/auth/create/Step1.tsx:150 msgid "Invite code" msgstr "Código de invitación" @@ -1986,17 +2005,17 @@ msgid "Jobs" msgstr "Tareas" #: src/view/com/modals/Waitlist.tsx:67 -msgid "Join the waitlist" -msgstr "Únete a la lista de espera" +#~ msgid "Join the waitlist" +#~ msgstr "Únete a la lista de espera" #: src/view/com/auth/create/Step1.tsx:174 #: src/view/com/auth/create/Step1.tsx:178 -msgid "Join the waitlist." -msgstr "Únete a la lista de espera." +#~ msgid "Join the waitlist." +#~ msgstr "Únete a la lista de espera." #: src/view/com/modals/Waitlist.tsx:128 -msgid "Join Waitlist" -msgstr "Únete a la lista de espera" +#~ msgid "Join Waitlist" +#~ msgstr "Únete a la lista de espera" #: src/screens/Onboarding/index.tsx:24 msgid "Journalism" @@ -2010,7 +2029,7 @@ msgstr "Escoger el idioma" msgid "Language settings" msgstr "" -#: src/Navigation.tsx:140 +#: src/Navigation.tsx:142 #: src/view/screens/LanguageSettings.tsx:89 msgid "Language Settings" msgstr "Configuración del idioma" @@ -2080,7 +2099,6 @@ msgid "Light" msgstr "" #: src/view/com/util/post-ctrls/PostCtrls.tsx:182 -#: src/view/com/util/post-ctrls/PostCtrls.tsx:216 msgid "Like" msgstr "" @@ -2088,7 +2106,7 @@ msgstr "" msgid "Like this feed" msgstr "Dar «me gusta» a esta noticia" -#: src/Navigation.tsx:197 +#: src/Navigation.tsx:199 msgid "Liked by" msgstr "Le ha gustado a" @@ -2121,7 +2139,7 @@ msgstr "Cantidad de «Me gusta»" msgid "Likes on this post" msgstr "" -#: src/Navigation.tsx:166 +#: src/Navigation.tsx:168 msgid "List" msgstr "" @@ -2157,7 +2175,7 @@ msgstr "" msgid "List unmuted" msgstr "" -#: src/Navigation.tsx:110 +#: src/Navigation.tsx:112 #: src/view/screens/Profile.tsx:185 #: src/view/shell/desktop/LeftNav.tsx:379 #: src/view/shell/Drawer.tsx:492 @@ -2189,7 +2207,7 @@ msgstr "Cargando..." #~ msgid "Local dev server" #~ msgstr "Servidor de desarrollo local" -#: src/Navigation.tsx:207 +#: src/Navigation.tsx:209 msgid "Log" msgstr "" @@ -2212,7 +2230,7 @@ msgstr "Acceder a una cuenta que no está en la lista" msgid "Make sure this is where you intend to go!" msgstr "¡Asegúrate de que es aquà a donde pretendes ir!" -#: src/components/dialogs/MutedWords.tsx:71 +#: src/components/dialogs/MutedWords.tsx:83 msgid "Manage your muted words and tags" msgstr "" @@ -2236,7 +2254,7 @@ msgstr "usuarios mencionados" msgid "Mentioned users" msgstr "Usuarios mencionados" -#: src/view/com/util/ViewHeader.tsx:81 +#: src/view/com/util/ViewHeader.tsx:87 #: src/view/screens/Search/Search.tsx:646 msgid "Menu" msgstr "Menú" @@ -2245,7 +2263,7 @@ msgstr "Menú" msgid "Message from server: {0}" msgstr "Mensaje del servidor: {0}" -#: src/Navigation.tsx:115 +#: src/Navigation.tsx:117 #: src/view/screens/Moderation.tsx:66 #: src/view/screens/Settings/index.tsx:625 #: src/view/shell/desktop/LeftNav.tsx:397 @@ -2259,13 +2277,13 @@ msgstr "Moderación" msgid "Moderation list by {0}" msgstr "" -#: src/view/screens/ProfileList.tsx:774 +#: src/view/screens/ProfileList.tsx:775 msgid "Moderation list by <0/>" msgstr "" #: src/view/com/lists/ListCard.tsx:91 #: src/view/com/modals/UserAddRemoveLists.tsx:204 -#: src/view/screens/ProfileList.tsx:772 +#: src/view/screens/ProfileList.tsx:773 msgid "Moderation list by you" msgstr "" @@ -2281,7 +2299,7 @@ msgstr "" msgid "Moderation lists" msgstr "Listas de moderación" -#: src/Navigation.tsx:120 +#: src/Navigation.tsx:122 #: src/view/screens/ModerationModlists.tsx:58 msgid "Moderation Lists" msgstr "Listas de moderación" @@ -2294,7 +2312,7 @@ msgstr "" msgid "Moderator has chosen to set a general warning on the content." msgstr "" -#: src/view/shell/desktop/Feeds.tsx:63 +#: src/view/shell/desktop/Feeds.tsx:65 msgid "More feeds" msgstr "Más canales de noticias" @@ -2305,8 +2323,8 @@ msgid "More options" msgstr "Más opciones" #: src/view/com/util/forms/PostDropdownBtn.tsx:315 -msgid "More post options" -msgstr "" +#~ msgid "More post options" +#~ msgstr "" #: src/view/screens/PreferencesThreads.tsx:82 msgid "Most-liked replies first" @@ -2316,11 +2334,11 @@ msgstr "" msgid "Must be at least 3 characters" msgstr "" -#: src/components/TagMenu/index.tsx:253 +#: src/components/TagMenu/index.tsx:249 msgid "Mute" msgstr "" -#: src/components/TagMenu/index.web.tsx:91 +#: src/components/TagMenu/index.web.tsx:105 msgid "Mute {truncatedTag}" msgstr "" @@ -2332,15 +2350,19 @@ msgstr "Silenciar la cuenta" msgid "Mute accounts" msgstr "Silenciar las cuentas" -#: src/components/TagMenu/index.tsx:211 -msgid "Mute all {tag} posts" +#: src/components/TagMenu/index.tsx:209 +msgid "Mute all {displayTag} posts" msgstr "" -#: src/components/dialogs/MutedWords.tsx:131 +#: src/components/TagMenu/index.tsx:211 +#~ msgid "Mute all {tag} posts" +#~ msgstr "" + +#: src/components/dialogs/MutedWords.tsx:149 msgid "Mute in tags only" msgstr "" -#: src/components/dialogs/MutedWords.tsx:116 +#: src/components/dialogs/MutedWords.tsx:134 msgid "Mute in text & tags" msgstr "" @@ -2356,19 +2378,21 @@ msgstr "¿Silenciar estas cuentas?" msgid "Mute this List" msgstr "" -#: src/components/dialogs/MutedWords.tsx:109 +#: src/components/dialogs/MutedWords.tsx:127 msgid "Mute this word in post text and tags" msgstr "" -#: src/components/dialogs/MutedWords.tsx:124 +#: src/components/dialogs/MutedWords.tsx:142 msgid "Mute this word in tags only" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:202 +#: src/view/com/util/forms/PostDropdownBtn.tsx:251 +#: src/view/com/util/forms/PostDropdownBtn.tsx:257 msgid "Mute thread" msgstr "Silenciar el hilo" -#: src/view/com/util/forms/PostDropdownBtn.tsx:216 +#: src/view/com/util/forms/PostDropdownBtn.tsx:267 +#: src/view/com/util/forms/PostDropdownBtn.tsx:269 msgid "Mute words & tags" msgstr "" @@ -2380,7 +2404,7 @@ msgstr "" msgid "Muted accounts" msgstr "Cuentas silenciadas" -#: src/Navigation.tsx:125 +#: src/Navigation.tsx:127 #: src/view/screens/ModerationMutedAccounts.tsx:107 msgid "Muted Accounts" msgstr "Cuentas silenciadas" @@ -2456,7 +2480,7 @@ msgstr "No pierdas nunca el acceso a tus seguidores y datos." msgid "Never lose access to your followers or data." msgstr "" -#: src/components/dialogs/MutedWords.tsx:244 +#: src/components/dialogs/MutedWords.tsx:293 msgid "Nevermind" msgstr "" @@ -2544,7 +2568,7 @@ msgid "No" msgstr "No" #: src/view/screens/ProfileFeed.tsx:584 -#: src/view/screens/ProfileList.tsx:754 +#: src/view/screens/ProfileList.tsx:755 msgid "No description" msgstr "Sin descripción" @@ -2561,6 +2585,10 @@ msgstr "" msgid "No result" msgstr "Sin resultados" +#: src/components/Lists.tsx:192 +msgid "No results found" +msgstr "" + #: src/view/screens/Feeds.tsx:495 msgid "No results found for \"{query}\"" msgstr "No se han encontrado resultados para \"{query}\"" @@ -2583,7 +2611,7 @@ msgstr "Nadie" msgid "Not Applicable." msgstr "No aplicable." -#: src/Navigation.tsx:105 +#: src/Navigation.tsx:107 #: src/view/screens/Profile.tsx:106 msgid "Not Found" msgstr "" @@ -2597,7 +2625,7 @@ msgstr "" msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites." msgstr "Nota: Bluesky es una red abierta y pública. Esta configuración sólo limita la visibilidad de tu contenido en la aplicación y el sitio web de Bluesky, y es posible que otras aplicaciones no respeten esta configuración. Otras aplicaciones y sitios web pueden seguir mostrando tu contenido a los usuarios que hayan cerrado sesión." -#: src/Navigation.tsx:450 +#: src/Navigation.tsx:457 #: src/view/screens/Notifications.tsx:124 #: src/view/screens/Notifications.tsx:148 #: src/view/shell/bottom-bar/BottomBar.tsx:205 @@ -2639,6 +2667,11 @@ msgstr "Falta el texto alternativo en una o varias imágenes." msgid "Only {0} can reply." msgstr "Solo {0} puede responder." +#: src/components/Lists.tsx:82 +msgid "Oops, something went wrong!" +msgstr "" + +#: src/components/Lists.tsx:188 #: src/view/screens/AppPasswords.tsx:65 #: src/view/screens/Profile.tsx:106 msgid "Oops!" @@ -2665,10 +2698,14 @@ msgstr "" msgid "Open muted words settings" msgstr "" -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:49 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:50 msgid "Open navigation" msgstr "Abrir navegación" +#: src/view/com/util/forms/PostDropdownBtn.tsx:175 +msgid "Open post options menu" +msgstr "" + #: src/view/screens/Settings/index.tsx:804 msgid "Open storybook page" msgstr "" @@ -2681,7 +2718,7 @@ msgstr "" msgid "Opens additional details for a debug entry" msgstr "" -#: src/view/com/notifications/FeedItem.tsx:348 +#: src/view/com/notifications/FeedItem.tsx:349 msgid "Opens an expanded list of users in this notification" msgstr "" @@ -2741,7 +2778,7 @@ msgstr "Abre la configuración de moderación" msgid "Opens password reset form" msgstr "" -#: src/view/com/home/HomeHeaderLayout.web.tsx:60 +#: src/view/com/home/HomeHeaderLayout.web.tsx:63 #: src/view/screens/Feeds.tsx:356 msgid "Opens screen to edit Saved Feeds" msgstr "" @@ -2790,6 +2827,7 @@ msgstr "Otra cuenta" msgid "Other..." msgstr "Otro..." +#: src/components/Lists.tsx:194 #: src/view/screens/NotFound.tsx:45 msgid "Page not found" msgstr "Página no encontrada" @@ -2798,8 +2836,8 @@ msgstr "Página no encontrada" msgid "Page Not Found" msgstr "" -#: src/view/com/auth/create/Step1.tsx:214 -#: src/view/com/auth/create/Step1.tsx:224 +#: src/view/com/auth/create/Step1.tsx:191 +#: src/view/com/auth/create/Step1.tsx:201 #: src/view/com/auth/login/LoginForm.tsx:226 #: src/view/com/auth/login/SetNewPasswordForm.tsx:161 #: src/view/com/modals/DeleteAccount.tsx:202 @@ -2814,11 +2852,11 @@ msgstr "Contraseña actualizada" msgid "Password updated!" msgstr "¡Contraseña actualizada!" -#: src/Navigation.tsx:160 +#: src/Navigation.tsx:162 msgid "People followed by @{0}" msgstr "" -#: src/Navigation.tsx:153 +#: src/Navigation.tsx:155 msgid "People following @{0}" msgstr "" @@ -2892,6 +2930,10 @@ msgstr "" msgid "Please enter a unique name for this App Password or use our randomly generated one." msgstr "Introduce un nombre único para la contraseña de esta app o utiliza una generada aleatoriamente." +#: src/components/dialogs/MutedWords.tsx:68 +msgid "Please enter a valid word, tag, or phrase to mute" +msgstr "" + #: src/view/com/auth/create/state.ts:170 #~ msgid "Please enter the code you received by SMS." #~ msgstr "" @@ -2944,13 +2986,13 @@ msgstr "Publicación" msgid "Post by {0}" msgstr "" -#: src/Navigation.tsx:172 -#: src/Navigation.tsx:179 -#: src/Navigation.tsx:186 +#: src/Navigation.tsx:174 +#: src/Navigation.tsx:181 +#: src/Navigation.tsx:188 msgid "Post by @{0}" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:90 +#: src/view/com/util/forms/PostDropdownBtn.tsx:108 msgid "Post deleted" msgstr "" @@ -2970,7 +3012,7 @@ msgstr "Lenguajes de la publicación" msgid "Post not found" msgstr "Publicación no encontrada" -#: src/components/TagMenu/index.tsx:257 +#: src/components/TagMenu/index.tsx:253 msgid "posts" msgstr "" @@ -2978,7 +3020,7 @@ msgstr "" msgid "Posts" msgstr "Publicaciones" -#: src/components/dialogs/MutedWords.tsx:77 +#: src/components/dialogs/MutedWords.tsx:90 msgid "Posts can be muted based on their text, their tags, or both." msgstr "" @@ -3007,7 +3049,7 @@ msgstr "Priorizar los usuarios a los que sigue" msgid "Privacy" msgstr "Privacidad" -#: src/Navigation.tsx:217 +#: src/Navigation.tsx:219 #: src/view/screens/PrivacyPolicy.tsx:29 #: src/view/screens/Settings/index.tsx:891 #: src/view/shell/Drawer.tsx:262 @@ -3084,7 +3126,7 @@ msgstr "Canales de noticias recomendados" msgid "Recommended Users" msgstr "Usuarios recomendados" -#: src/components/dialogs/MutedWords.tsx:249 +#: src/components/dialogs/MutedWords.tsx:298 #: src/view/com/modals/ListAddRemoveUsers.tsx:264 #: src/view/com/modals/SelfLabel.tsx:83 #: src/view/com/modals/UserAddRemoveLists.tsx:219 @@ -3122,7 +3164,7 @@ msgstr "Eliminar la imagen" msgid "Remove image preview" msgstr "Eliminar la vista previa de la imagen" -#: src/components/dialogs/MutedWords.tsx:294 +#: src/components/dialogs/MutedWords.tsx:343 msgid "Remove mute word from your list" msgstr "" @@ -3192,7 +3234,8 @@ msgid "Report List" msgstr "Informe de la lista" #: src/view/com/modals/report/SendReportButton.tsx:37 -#: src/view/com/util/forms/PostDropdownBtn.tsx:255 +#: src/view/com/util/forms/PostDropdownBtn.tsx:301 +#: src/view/com/util/forms/PostDropdownBtn.tsx:309 msgid "Report post" msgstr "Informe de la publicación" @@ -3251,7 +3294,7 @@ msgstr "" msgid "Require alt text before posting" msgstr "" -#: src/view/com/auth/create/Step1.tsx:153 +#: src/view/com/auth/create/Step1.tsx:146 msgid "Required for this provider" msgstr "Requerido para este proveedor" @@ -3316,7 +3359,7 @@ msgstr "Volver a intentar" #~ msgid "Retry." #~ msgstr "" -#: src/view/screens/ProfileList.tsx:898 +#: src/view/screens/ProfileList.tsx:903 msgid "Return to previous page" msgstr "" @@ -3371,11 +3414,11 @@ msgstr "" msgid "Science" msgstr "" -#: src/view/screens/ProfileList.tsx:854 +#: src/view/screens/ProfileList.tsx:859 msgid "Scroll to top" msgstr "" -#: src/Navigation.tsx:440 +#: src/Navigation.tsx:447 #: src/view/com/auth/LoggedOut.tsx:122 #: src/view/com/modals/ListAddRemoveUsers.tsx:75 #: src/view/com/util/forms/SearchInput.tsx:67 @@ -3398,13 +3441,21 @@ msgid "Search for \"{query}\"" msgstr "" #: src/components/TagMenu/index.tsx:145 -msgid "Search for all posts by @{authorHandle} with tag {tag}" +msgid "Search for all posts by @{authorHandle} with tag {displayTag}" msgstr "" -#: src/components/TagMenu/index.tsx:90 -msgid "Search for all posts with tag {tag}" +#: src/components/TagMenu/index.tsx:145 +#~ msgid "Search for all posts by @{authorHandle} with tag {tag}" +#~ msgstr "" + +#: src/components/TagMenu/index.tsx:94 +msgid "Search for all posts with tag {displayTag}" msgstr "" +#: src/components/TagMenu/index.tsx:90 +#~ msgid "Search for all posts with tag {tag}" +#~ msgstr "" + #: src/view/com/auth/LoggedOut.tsx:104 #: src/view/com/auth/LoggedOut.tsx:105 #: src/view/com/modals/ListAddRemoveUsers.tsx:70 @@ -3415,22 +3466,30 @@ msgstr "Buscar usuarios" msgid "Security Step Required" msgstr "Se requiere un paso de seguridad" -#: src/components/TagMenu/index.web.tsx:50 +#: src/components/TagMenu/index.web.tsx:66 msgid "See {truncatedTag} posts" msgstr "" -#: src/components/TagMenu/index.web.tsx:67 +#: src/components/TagMenu/index.web.tsx:83 msgid "See {truncatedTag} posts by user" msgstr "" #: src/components/TagMenu/index.tsx:128 -msgid "See <0>{tag}</0> posts" +msgid "See <0>{displayTag}</0> posts" msgstr "" -#: src/components/TagMenu/index.tsx:189 -msgid "See <0>{tag}</0> posts by this user" +#: src/components/TagMenu/index.tsx:187 +msgid "See <0>{displayTag}</0> posts by this user" msgstr "" +#: src/components/TagMenu/index.tsx:128 +#~ msgid "See <0>{tag}</0> posts" +#~ msgstr "" + +#: src/components/TagMenu/index.tsx:189 +#~ msgid "See <0>{tag}</0> posts by this user" +#~ msgstr "" + #: src/view/screens/SavedFeeds.tsx:163 msgid "See this guide" msgstr "" @@ -3455,7 +3514,7 @@ msgstr "Selecciona de una cuenta existente" msgid "Select option {i} of {numItems}" msgstr "" -#: src/view/com/auth/create/Step1.tsx:103 +#: src/view/com/auth/create/Step1.tsx:96 #: src/view/com/auth/login/LoginForm.tsx:150 msgid "Select service" msgstr "Selecciona el servicio" @@ -3573,7 +3632,7 @@ msgstr "" msgid "Set new password" msgstr "Establecer la contraseña nueva" -#: src/view/com/auth/create/Step1.tsx:225 +#: src/view/com/auth/create/Step1.tsx:202 msgid "Set password" msgstr "" @@ -3617,12 +3676,12 @@ msgstr "" msgid "Sets hosting provider for password reset" msgstr "" -#: src/view/com/auth/create/Step1.tsx:104 +#: src/view/com/auth/create/Step1.tsx:97 #: src/view/com/auth/login/LoginForm.tsx:151 msgid "Sets server for the Bluesky client" msgstr "" -#: src/Navigation.tsx:135 +#: src/Navigation.tsx:137 #: src/view/screens/Settings/index.tsx:294 #: src/view/shell/desktop/LeftNav.tsx:433 #: src/view/shell/Drawer.tsx:567 @@ -3640,7 +3699,9 @@ msgid "Share" msgstr "" #: src/view/com/profile/ProfileHeader.tsx:295 -#: src/view/com/util/forms/PostDropdownBtn.tsx:184 +#: src/view/com/util/forms/PostDropdownBtn.tsx:231 +#: src/view/com/util/forms/PostDropdownBtn.tsx:237 +#: src/view/com/util/post-ctrls/PostCtrls.tsx:215 #: src/view/screens/ProfileList.tsx:418 msgid "Share" msgstr "Compartir" @@ -3732,7 +3793,7 @@ msgstr "" msgid "Show the content" msgstr "" -#: src/view/com/notifications/FeedItem.tsx:346 +#: src/view/com/notifications/FeedItem.tsx:347 msgid "Show users" msgstr "Mostrar usuarios" @@ -3839,11 +3900,15 @@ msgstr "" #~ msgid "Something went wrong and we're not sure what." #~ msgstr "" -#: src/view/com/modals/Waitlist.tsx:51 -msgid "Something went wrong. Check your email and try again." +#: src/components/Lists.tsx:203 +msgid "Something went wrong!" msgstr "" -#: src/App.native.tsx:63 +#: src/view/com/modals/Waitlist.tsx:51 +#~ msgid "Something went wrong. Check your email and try again." +#~ msgstr "" + +#: src/App.native.tsx:66 msgid "Sorry! Your session expired. Please log in again." msgstr "" @@ -3879,7 +3944,7 @@ msgstr "" msgid "Storage cleared, you need to restart the app now." msgstr "" -#: src/Navigation.tsx:202 +#: src/Navigation.tsx:204 #: src/view/screens/Settings/index.tsx:807 msgid "Storybook" msgstr "Libro de cuentos" @@ -3893,7 +3958,7 @@ msgid "Subscribe" msgstr "Suscribirse" #: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:173 -#: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:307 +#: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:308 msgid "Subscribe to the {0} feed" msgstr "" @@ -3913,7 +3978,7 @@ msgstr "" msgid "Suggestive" msgstr "" -#: src/Navigation.tsx:212 +#: src/Navigation.tsx:214 #: src/view/screens/Support.tsx:30 #: src/view/screens/Support.tsx:33 msgid "Support" @@ -3945,14 +4010,18 @@ msgstr "" msgid "System log" msgstr "Bitácora del sistema" -#: src/components/dialogs/MutedWords.tsx:288 +#: src/components/dialogs/MutedWords.tsx:337 msgid "tag" msgstr "" -#: src/components/TagMenu/index.tsx:74 -msgid "Tag menu: {tag}" +#: src/components/TagMenu/index.tsx:78 +msgid "Tag menu: {displayTag}" msgstr "" +#: src/components/TagMenu/index.tsx:74 +#~ msgid "Tag menu: {tag}" +#~ msgstr "" + #: src/view/com/modals/crop-image/CropImage.web.tsx:112 msgid "Tall" msgstr "Alto" @@ -3969,14 +4038,14 @@ msgstr "" msgid "Terms" msgstr "Condiciones" -#: src/Navigation.tsx:222 +#: src/Navigation.tsx:224 #: src/view/screens/Settings/index.tsx:885 #: src/view/screens/TermsOfService.tsx:29 #: src/view/shell/Drawer.tsx:256 msgid "Terms of Service" msgstr "Condiciones de servicio" -#: src/components/dialogs/MutedWords.tsx:288 +#: src/components/dialogs/MutedWords.tsx:337 msgid "text" msgstr "" @@ -4057,7 +4126,7 @@ msgstr "" msgid "There was an issue fetching notifications. Tap here to try again." msgstr "" -#: src/view/com/posts/Feed.tsx:263 +#: src/view/com/posts/Feed.tsx:265 msgid "There was an issue fetching posts. Tap here to try again." msgstr "" @@ -4163,7 +4232,7 @@ msgstr "Esto es importante por si alguna vez necesitas cambiar tu correo electrà msgid "This link is taking you to the following website:" msgstr "Este enlace te lleva al siguiente sitio web:" -#: src/view/screens/ProfileList.tsx:834 +#: src/view/screens/ProfileList.tsx:839 msgid "This list is empty!" msgstr "" @@ -4195,11 +4264,11 @@ msgstr "" msgid "This warning is only available for posts with media attached." msgstr "Esta advertencia sólo está disponible para las publicaciones con medios adjuntos." -#: src/components/dialogs/MutedWords.tsx:236 +#: src/components/dialogs/MutedWords.tsx:285 msgid "This will delete {0} from your muted words. You can always add it back later." msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:237 +#: src/view/com/util/forms/PostDropdownBtn.tsx:282 msgid "This will hide this post from your feeds." msgstr "Esto ocultará esta entrada de tus contenidos." @@ -4212,11 +4281,11 @@ msgstr "Preferencias de hilos" msgid "Threaded Mode" msgstr "Modo con hilos" -#: src/Navigation.tsx:255 +#: src/Navigation.tsx:257 msgid "Threads Preferences" msgstr "" -#: src/components/dialogs/MutedWords.tsx:95 +#: src/components/dialogs/MutedWords.tsx:113 msgid "Toggle between muted word options." msgstr "" @@ -4230,7 +4299,8 @@ msgstr "Transformaciones" #: src/view/com/post-thread/PostThreadItem.tsx:685 #: src/view/com/post-thread/PostThreadItem.tsx:687 -#: src/view/com/util/forms/PostDropdownBtn.tsx:156 +#: src/view/com/util/forms/PostDropdownBtn.tsx:215 +#: src/view/com/util/forms/PostDropdownBtn.tsx:217 msgid "Translate" msgstr "Traducir" @@ -4291,16 +4361,15 @@ msgid "Unfortunately, you do not meet the requirements to create an account." msgstr "Lamentablemente, no cumples los requisitos para crear una cuenta." #: src/view/com/util/post-ctrls/PostCtrls.tsx:182 -#: src/view/com/util/post-ctrls/PostCtrls.tsx:216 msgid "Unlike" msgstr "" -#: src/components/TagMenu/index.tsx:253 +#: src/components/TagMenu/index.tsx:249 #: src/view/screens/ProfileList.tsx:597 msgid "Unmute" msgstr "" -#: src/components/TagMenu/index.web.tsx:90 +#: src/components/TagMenu/index.web.tsx:104 msgid "Unmute {truncatedTag}" msgstr "" @@ -4308,11 +4377,16 @@ msgstr "" msgid "Unmute Account" msgstr "Desactivar la opción de silenciar la cuenta" -#: src/components/TagMenu/index.tsx:210 -msgid "Unmute all {tag} posts" +#: src/components/TagMenu/index.tsx:208 +msgid "Unmute all {displayTag} posts" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:202 +#: src/components/TagMenu/index.tsx:210 +#~ msgid "Unmute all {tag} posts" +#~ msgstr "" + +#: src/view/com/util/forms/PostDropdownBtn.tsx:251 +#: src/view/com/util/forms/PostDropdownBtn.tsx:256 msgid "Unmute thread" msgstr "Desactivar la opción de silenciar el hilo" @@ -4396,13 +4470,13 @@ msgstr "Identificador del usuario" msgid "User list by {0}" msgstr "" -#: src/view/screens/ProfileList.tsx:762 +#: src/view/screens/ProfileList.tsx:763 msgid "User list by <0/>" msgstr "" #: src/view/com/lists/ListCard.tsx:83 #: src/view/com/modals/UserAddRemoveLists.tsx:196 -#: src/view/screens/ProfileList.tsx:760 +#: src/view/screens/ProfileList.tsx:761 msgid "User list by you" msgstr "" @@ -4423,7 +4497,7 @@ msgstr "Listas de usuarios" msgid "Username or email address" msgstr "Nombre de usuario o dirección de correo electrónico" -#: src/view/screens/ProfileList.tsx:796 +#: src/view/screens/ProfileList.tsx:797 msgid "Users" msgstr "Usuarios" @@ -4497,6 +4571,10 @@ msgstr "" msgid "We also think you'll like \"For You\" by Skygaze:" msgstr "" +#: src/screens/Hashtag.tsx:132 +msgid "We couldn't find any results for that hashtag." +msgstr "" + #: src/screens/Deactivated.tsx:133 msgid "We estimate {estimatedTime} until your account is ready." msgstr "" @@ -4513,7 +4591,7 @@ msgstr "" #~ msgid "We recommend \"For You\" by Skygaze:" #~ msgstr "" -#: src/components/dialogs/MutedWords.tsx:161 +#: src/components/dialogs/MutedWords.tsx:204 msgid "We recommend avoiding common words that appear in many posts, since it can result in no posts being shown." msgstr "" @@ -4545,7 +4623,7 @@ msgstr "¡Nos hace mucha ilusión que te unas a nosotros!" msgid "We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @{handleOrDid}." msgstr "" -#: src/components/dialogs/MutedWords.tsx:182 +#: src/components/dialogs/MutedWords.tsx:230 msgid "We're sorry, but we weren't able to load your muted words at this time. Please try again." msgstr "" @@ -4553,6 +4631,7 @@ msgstr "" msgid "We're sorry, but your search could not be completed. Please try again in a few minutes." msgstr "Lo sentimos, pero no se ha podido completar tu búsqueda. Vuelve a intentarlo dentro de unos minutos." +#: src/components/Lists.tsx:211 #: src/view/screens/NotFound.tsx:48 msgid "We're sorry! We can't find the page you were looking for." msgstr "Lo sentimos. No encontramos la página que buscabas." @@ -4700,7 +4779,7 @@ msgstr "Aún no has creado ninguna contraseña de aplicación. Puedes crear una msgid "You have not muted any accounts yet. To mute an account, go to their profile and selected \"Mute account\" from the menu on their account." msgstr "Aún no has silenciado ninguna cuenta. Para silenciar una cuenta, ve a su perfil y selecciona \"Silenciar cuenta\" en el menú de su cuenta." -#: src/components/dialogs/MutedWords.tsx:202 +#: src/components/dialogs/MutedWords.tsx:250 msgid "You haven't muted any words or tags yet" msgstr "" @@ -4712,11 +4791,11 @@ msgstr "" msgid "You must be 18 years or older to enable adult content" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:129 +#: src/view/com/util/forms/PostDropdownBtn.tsx:147 msgid "You will no longer receive notifications for this thread" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:132 +#: src/view/com/util/forms/PostDropdownBtn.tsx:150 msgid "You will now receive notifications for this thread" msgstr "" @@ -4742,7 +4821,7 @@ msgstr "" msgid "You've reached the end of your feed! Find some more accounts to follow." msgstr "" -#: src/view/com/auth/create/Step1.tsx:74 +#: src/view/com/auth/create/Step1.tsx:67 msgid "Your account" msgstr "Tu cuenta" @@ -4754,7 +4833,7 @@ msgstr "" msgid "Your account repository, containing all public data records, can be downloaded as a \"CAR\" file. This file does not include media embeds, such as images, or your private data, which must be fetched separately." msgstr "" -#: src/view/com/auth/create/Step1.tsx:238 +#: src/view/com/auth/create/Step1.tsx:215 msgid "Your birth date" msgstr "Tu fecha de nacimiento" @@ -4773,8 +4852,8 @@ msgid "Your email appears to be invalid." msgstr "Tu correo electrónico parece no ser válido." #: src/view/com/modals/Waitlist.tsx:109 -msgid "Your email has been saved! We'll be in touch soon." -msgstr "¡Hemos guardado tu correo electrónico! Pronto nos pondremos en contacto contigo." +#~ msgid "Your email has been saved! We'll be in touch soon." +#~ msgstr "¡Hemos guardado tu correo electrónico! Pronto nos pondremos en contacto contigo." #: src/view/com/modals/ChangeEmail.tsx:125 msgid "Your email has been updated but not verified. As a next step, please verify your new email." @@ -4802,7 +4881,7 @@ msgstr "" #~ msgid "Your invite codes are hidden when logged in using an App Password" #~ msgstr "Tus códigos de invitación están ocultos cuando inicias sesión con una contraseña de la app" -#: src/components/dialogs/MutedWords.tsx:173 +#: src/components/dialogs/MutedWords.tsx:221 msgid "Your muted words" msgstr "" diff --git a/src/locale/locales/fr/messages.po b/src/locale/locales/fr/messages.po index 44b9fb9a2..37af8b386 100644 --- a/src/locale/locales/fr/messages.po +++ b/src/locale/locales/fr/messages.po @@ -8,41 +8,19 @@ msgstr "" "Language: fr\n" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: \n" -"Last-Translator: Stanislas Signoud (@signez.fr)\n" -"Language-Team: \n" +"PO-Revision-Date: 2024-03-12 09:00+0000\n" +"Last-Translator: surfdude29\n" +"Language-Team: Stanislas Signoud (@signez.fr), surfdude29\n" "Plural-Forms: \n" #: src/view/com/modals/VerifyEmail.tsx:142 msgid "(no email)" msgstr "(pas d’e-mail)" -#: src/view/shell/desktop/RightNav.tsx:168 -#~ msgid "{0, plural, one {# invite code available} other {# invite codes available}}" -#~ msgstr "{0, plural, one {# code d’invitation disponible} other {# codes d’invitations disponibles}}" - #: src/view/com/profile/ProfileHeader.tsx:593 msgid "{following} following" msgstr "{following} abonnements" -#: src/view/shell/desktop/RightNav.tsx:151 -#~ msgid "{invitesAvailable, plural, one {Invite codes: # available} other {Invite codes: # available}}" -#~ msgstr "{invitesAvailable, plural, one {Code d’invitation : # disponible} other {Codes d’invitation : # disponibles}}" - -#: src/view/screens/Settings.tsx:435 -#: src/view/shell/Drawer.tsx:664 -#~ msgid "{invitesAvailable} invite code available" -#~ msgstr "{invitesAvailable} code d’invitation disponible" - -#: src/view/screens/Settings.tsx:437 -#: src/view/shell/Drawer.tsx:666 -#~ msgid "{invitesAvailable} invite codes available" -#~ msgstr "{invitesAvailable} codes d’invitation disponibles" - -#: src/view/screens/Search/Search.tsx:87 -#~ msgid "{message}" -#~ msgstr "{message}" - #: src/view/shell/Drawer.tsx:440 msgid "{numUnreadNotifications} unread" msgstr "{numUnreadNotifications} non lus" @@ -57,7 +35,7 @@ msgstr "<0>{following} </0><1>abonnements</1>" #: src/view/com/auth/onboarding/RecommendedFeeds.tsx:30 msgid "<0>Choose your</0><1>Recommended</1><2>Feeds</2>" -msgstr "<0>Choisissez vos</0><1>fils d’actualité</1><2>recommandés</2>" +msgstr "<0>Choisissez vos</0><1>fils d’actu</1><2>recommandés</2>" #: src/view/com/auth/onboarding/RecommendedFollows.tsx:37 msgid "<0>Follow some</0><1>Recommended</1><2>Users</2>" @@ -79,12 +57,12 @@ msgstr "Un avertissement sur le contenu a été appliqué sur ce {0}." msgid "A new version of the app is available. Please update to continue using the app." msgstr "Une nouvelle version de l’application est disponible. Veuillez faire la mise à jour pour continuer à utiliser l’application." -#: src/view/com/util/ViewHeader.tsx:83 +#: src/view/com/util/ViewHeader.tsx:89 #: src/view/screens/Search/Search.tsx:647 msgid "Access navigation links and settings" msgstr "Accède aux liens de navigation et aux paramètres" -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:51 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:52 msgid "Access profile and other navigation links" msgstr "Accède au profil et aux autres liens de navigation" @@ -131,11 +109,11 @@ msgstr "Compte débloqué" msgid "Account unmuted" msgstr "Compte démasqué" -#: src/components/dialogs/MutedWords.tsx:147 +#: src/components/dialogs/MutedWords.tsx:165 #: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:150 #: src/view/com/modals/ListAddRemoveUsers.tsx:264 #: src/view/com/modals/UserAddRemoveLists.tsx:219 -#: src/view/screens/ProfileList.tsx:812 +#: src/view/screens/ProfileList.tsx:813 msgid "Add" msgstr "Ajouter" @@ -143,7 +121,7 @@ msgstr "Ajouter" msgid "Add a content warning" msgstr "Ajouter un avertissement sur le contenu" -#: src/view/screens/ProfileList.tsx:802 +#: src/view/screens/ProfileList.tsx:803 msgid "Add a user to this list" msgstr "Ajouter un compte à cette liste" @@ -179,19 +157,19 @@ msgstr "Ajouter une carte de lien" #: src/view/com/composer/Composer.tsx:458 msgid "Add link card:" -msgstr "Ajouter une carte de lien :" +msgstr "Ajouter une carte de lien :" -#: src/components/dialogs/MutedWords.tsx:140 +#: src/components/dialogs/MutedWords.tsx:158 msgid "Add mute word for configured settings" -msgstr "" +msgstr "Ajouter un mot masqué pour les paramètres configurés" -#: src/components/dialogs/MutedWords.tsx:74 +#: src/components/dialogs/MutedWords.tsx:87 msgid "Add muted words and tags" -msgstr "" +msgstr "Ajouter des mots et des mots-clés masqués" #: src/view/com/modals/ChangeHandle.tsx:417 msgid "Add the following DNS record to your domain:" -msgstr "Ajoutez l’enregistrement DNS suivant à votre domaine :" +msgstr "Ajoutez l’enregistrement DNS suivant à votre domaine :" #: src/view/com/profile/ProfileHeader.tsx:310 msgid "Add to Lists" @@ -217,7 +195,7 @@ msgstr "Ajouté à mes fils d’actu" #: src/view/screens/PreferencesFollowingFeed.tsx:173 msgid "Adjust the number of likes a reply must have to be shown in your feed." -msgstr "Définissez le nombre de likes qu’une réponse doit avoir pour être affichée dans votre fil d’actualité." +msgstr "Définissez le nombre de likes qu’une réponse doit avoir pour être affichée dans votre fil d’actu." #: src/view/com/modals/SelfLabel.tsx:75 msgid "Adult Content" @@ -227,22 +205,18 @@ msgstr "Contenu pour adultes" msgid "Adult content can only be enabled via the Web at <0/>." msgstr "Le contenu pour adultes ne peut être activé que via le Web à <0/>." -#: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:78 -#~ msgid "Adult content can only be enabled via the Web at <0>bsky.app</0>." -#~ msgstr "" - #: src/view/screens/Settings/index.tsx:664 msgid "Advanced" msgstr "Avancé" #: src/view/screens/Feeds.tsx:666 msgid "All the feeds you've saved, right in one place." -msgstr "" +msgstr "Tous les fils d’actu que vous avez enregistrés, au même endroit." #: src/view/com/auth/login/ForgotPasswordForm.tsx:221 #: src/view/com/modals/ChangePassword.tsx:168 msgid "Already have a code?" -msgstr "" +msgstr "Avez-vous déjà un code ?" #: src/view/com/auth/login/ChooseAccountForm.tsx:98 msgid "Already signed in as @{0}" @@ -273,14 +247,14 @@ msgstr "Un courriel a été envoyé à votre ancienne adresse, {0}. Il comprend msgid "An issue occurred, please try again." msgstr "Un problème est survenu, veuillez réessayer." -#: src/view/com/notifications/FeedItem.tsx:236 +#: src/view/com/notifications/FeedItem.tsx:237 #: src/view/com/threadgate/WhoCanReply.tsx:178 msgid "and" msgstr "et" #: src/screens/Onboarding/index.tsx:32 msgid "Animals" -msgstr "" +msgstr "Animaux" #: src/view/screens/LanguageSettings.tsx:95 msgid "App Language" @@ -302,23 +276,20 @@ msgstr "Les noms de mots de passe d’application doivent comporter au moins 4 c msgid "App password settings" msgstr "Paramètres de mot de passe d’application" -#: src/view/screens/Settings.tsx:650 -#~ msgid "App passwords" -#~ msgstr "Mots de passe d’application" - -#: src/Navigation.tsx:237 +#: src/Navigation.tsx:239 #: src/view/screens/AppPasswords.tsx:187 #: src/view/screens/Settings/index.tsx:684 msgid "App Passwords" msgstr "Mots de passe d’application" -#: src/view/com/util/forms/PostDropdownBtn.tsx:295 +#: src/view/com/util/forms/PostDropdownBtn.tsx:337 +#: src/view/com/util/forms/PostDropdownBtn.tsx:346 msgid "Appeal content warning" msgstr "Faire appel de l’avertissement sur le contenu" #: src/view/com/modals/AppealLabel.tsx:65 msgid "Appeal Content Warning" -msgstr "Appel de l’avertissement sur le contenu" +msgstr "Faire appel de l’avertissement sur le contenu" #: src/view/com/util/moderation/LabelInfo.tsx:52 msgid "Appeal this decision" @@ -334,28 +305,28 @@ msgstr "Affichage" #: src/view/screens/AppPasswords.tsx:224 msgid "Are you sure you want to delete the app password \"{name}\"?" -msgstr "Êtes-vous sûr de vouloir supprimer le mot de passe de l’application « {name} » ?" +msgstr "Êtes-vous sûr de vouloir supprimer le mot de passe de l’application « {name} » ?" #: src/view/com/composer/Composer.tsx:150 msgid "Are you sure you'd like to discard this draft?" -msgstr "Êtes-vous sûr de vouloir rejeter ce brouillon ?" +msgstr "Êtes-vous sûr de vouloir rejeter ce brouillon ?" -#: src/components/dialogs/MutedWords.tsx:233 +#: src/components/dialogs/MutedWords.tsx:282 #: src/view/screens/ProfileList.tsx:365 msgid "Are you sure?" -msgstr "Vous confirmez ?" +msgstr "Vous confirmez ?" -#: src/view/com/util/forms/PostDropdownBtn.tsx:278 +#: src/view/com/util/forms/PostDropdownBtn.tsx:322 msgid "Are you sure? This cannot be undone." -msgstr "Vous confirmez ? Cela ne pourra pas être annulé." +msgstr "Vous confirmez ? Cela ne pourra pas être annulé." #: src/view/com/composer/select-language/SuggestedLanguage.tsx:60 msgid "Are you writing in <0>{0}</0>?" -msgstr "" +msgstr "Écrivez-vous en <0>{0}</0> ?" #: src/screens/Onboarding/index.tsx:26 msgid "Art" -msgstr "" +msgstr "Art" #: src/view/com/modals/SelfLabel.tsx:123 msgid "Artistic or non-erotic nudity." @@ -371,7 +342,7 @@ msgstr "Nudité artistique ou non érotique." #: src/view/com/post-thread/PostThread.tsx:522 #: src/view/com/post-thread/PostThread.tsx:530 #: src/view/com/profile/ProfileHeader.tsx:649 -#: src/view/com/util/ViewHeader.tsx:81 +#: src/view/com/util/ViewHeader.tsx:87 msgid "Back" msgstr "Arrière" @@ -382,20 +353,20 @@ msgstr "Retour" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:136 msgid "Based on your interest in {interestsText}" -msgstr "" +msgstr "En fonction de votre intérêt pour {interestsText}" #: src/view/screens/Settings/index.tsx:523 msgid "Basics" msgstr "Principes de base" -#: src/view/com/auth/create/Step1.tsx:250 +#: src/view/com/auth/create/Step1.tsx:227 #: src/view/com/modals/BirthDateSettings.tsx:73 msgid "Birthday" msgstr "Date de naissance" #: src/view/screens/Settings/index.tsx:340 msgid "Birthday:" -msgstr "Date de naissance :" +msgstr "Date de naissance :" #: src/view/com/profile/ProfileHeader.tsx:239 #: src/view/com/profile/ProfileHeader.tsx:346 @@ -412,7 +383,7 @@ msgstr "Liste de blocage" #: src/view/screens/ProfileList.tsx:316 msgid "Block these accounts?" -msgstr "Bloquer ces comptes ?" +msgstr "Bloquer ces comptes ?" #: src/view/screens/ProfileList.tsx:320 msgid "Block this List" @@ -427,7 +398,7 @@ msgstr "Bloqué" msgid "Blocked accounts" msgstr "Comptes bloqués" -#: src/Navigation.tsx:130 +#: src/Navigation.tsx:132 #: src/view/screens/ModerationBlockedAccounts.tsx:107 msgid "Blocked Accounts" msgstr "Comptes bloqués" @@ -461,7 +432,7 @@ msgstr "Bluesky" #: src/view/com/auth/server-input/index.tsx:150 msgid "Bluesky is an open network where you can choose your hosting provider. Custom hosting is now available in beta for developers." -msgstr "" +msgstr "Bluesky est un réseau ouvert où vous pouvez choisir votre hébergeur. L’auto-hébergement est désormais disponible en version bêta pour les développeurs." #: src/view/com/auth/onboarding/WelcomeDesktop.tsx:80 #: src/view/com/auth/onboarding/WelcomeMobile.tsx:80 @@ -478,21 +449,13 @@ msgstr "Bluesky est ouvert." msgid "Bluesky is public." msgstr "Bluesky est public." -#: src/view/com/modals/Waitlist.tsx:70 -msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon." -msgstr "Bluesky distribue des invitations pour construire une communauté plus saine. Si personne ne peut vous donner une invitation, vous pouvez vous inscrire sur notre liste d’attente et nous vous en enverrons une bientôt." - #: src/view/screens/Moderation.tsx:245 msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private." -msgstr "Bluesky n’affichera pas votre profil et vos messages à des personnes non connectées. Il est possible que d’autres applications n’honorent pas cette demande. Cela ne privatise pas votre compte." - -#: src/view/com/modals/ServerInput.tsx:78 -#~ msgid "Bluesky.Social" -#~ msgstr "Bluesky.Social" +msgstr "Bluesky n’affichera pas votre profil et vos posts à des personnes non connectées. Il est possible que d’autres applications n’honorent pas cette demande. Cela ne privatise pas votre compte." #: src/screens/Onboarding/index.tsx:33 msgid "Books" -msgstr "" +msgstr "Livres" #: src/view/screens/Settings/index.tsx:859 msgid "Build version {0} {1}" @@ -503,10 +466,6 @@ msgstr "Version Build {0} {1}" msgid "Business" msgstr "Affaires" -#: src/view/com/modals/ServerInput.tsx:115 -#~ msgid "Button disabled. Input custom domain to proceed." -#~ msgstr "Bouton désactivé. Saisissez un domaine personnalisé pour continuer." - #: src/view/com/profile/ProfileSubpageHeader.tsx:157 msgid "by —" msgstr "par —" @@ -533,7 +492,7 @@ msgstr "Caméra" msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must be at least 4 characters long, but no more than 32 characters long." msgstr "Ne peut contenir que des lettres, des chiffres, des espaces, des tirets et des tirets bas. La longueur doit être d’au moins 4 caractères, mais pas plus de 32." -#: src/components/Prompt.tsx:91 +#: src/components/Prompt.tsx:101 #: src/view/com/composer/Composer.tsx:307 #: src/view/com/composer/Composer.tsx:312 #: src/view/com/modals/ChangeEmail.tsx:218 @@ -548,7 +507,6 @@ msgstr "Ne peut contenir que des lettres, des chiffres, des espaces, des tirets #: src/view/com/modals/Repost.tsx:87 #: src/view/com/modals/VerifyEmail.tsx:247 #: src/view/com/modals/VerifyEmail.tsx:253 -#: src/view/com/modals/Waitlist.tsx:142 #: src/view/screens/Search/Search.tsx:716 #: src/view/shell/desktop/Search.tsx:238 msgid "Cancel" @@ -589,10 +547,6 @@ msgstr "Annuler la citation" msgid "Cancel search" msgstr "Annuler la recherche" -#: src/view/com/modals/Waitlist.tsx:136 -msgid "Cancel waitlist signup" -msgstr "Annuler l’inscription sur la liste d’attente" - #: src/view/screens/Settings/index.tsx:334 msgctxt "action" msgid "Change" @@ -613,19 +567,19 @@ msgstr "Modifier mon e-mail" #: src/view/screens/Settings/index.tsx:732 msgid "Change password" -msgstr "" +msgstr "Modifier le mot de passe" #: src/view/screens/Settings/index.tsx:741 msgid "Change Password" -msgstr "" +msgstr "Modifier le mot de passe" #: src/view/com/composer/select-language/SuggestedLanguage.tsx:73 msgid "Change post language to {0}" -msgstr "" +msgstr "Modifier la langue de post en {0}" #: src/view/screens/Settings/index.tsx:733 msgid "Change your Bluesky password" -msgstr "" +msgstr "Changer votre mot de passe pour Bluesky" #: src/view/com/modals/ChangeEmail.tsx:109 msgid "Change Your Email" @@ -634,11 +588,11 @@ msgstr "Modifier votre e-mail" #: src/screens/Deactivated.tsx:72 #: src/screens/Deactivated.tsx:76 msgid "Check my status" -msgstr "" +msgstr "Vérifier mon statut" #: src/view/com/auth/onboarding/RecommendedFeeds.tsx:121 msgid "Check out some recommended feeds. Tap + to add them to your list of pinned feeds." -msgstr "Consultez quelques fils d’actu recommandés. Appuyez sur + pour les ajouter à votre liste de fils d’actualité." +msgstr "Consultez quelques fils d’actu recommandés. Appuyez sur + pour les ajouter à votre liste de fils d’actu." #: src/view/com/auth/onboarding/RecommendedFollows.tsx:185 msgid "Check out some recommended users. Follow them to see similar users." @@ -646,11 +600,11 @@ msgstr "Consultez quelques comptes recommandés. Suivez-les pour voir des person #: src/view/com/modals/DeleteAccount.tsx:169 msgid "Check your inbox for an email with the confirmation code to enter below:" -msgstr "Consultez votre boîte de réception, vous avez du recevoir un e-mail contenant un code de confirmation à saisir ci-dessous :" +msgstr "Consultez votre boîte de réception, vous avez du recevoir un e-mail contenant un code de confirmation à saisir ci-dessous :" #: src/view/com/modals/Threadgate.tsx:72 msgid "Choose \"Everybody\" or \"Nobody\"" -msgstr "Choisir « Tout le monde » ou « Personne »" +msgstr "Choisir « Tout le monde » ou « Personne »" #: src/view/screens/Settings/index.tsx:697 msgid "Choose a new Bluesky username or create" @@ -662,22 +616,18 @@ msgstr "Choisir un service" #: src/screens/Onboarding/StepFinished.tsx:135 msgid "Choose the algorithms that power your custom feeds." -msgstr "" +msgstr "Choisissez les algorithmes qui alimentent vos fils d’actu personnalisés." #: src/view/com/auth/onboarding/WelcomeDesktop.tsx:83 #: src/view/com/auth/onboarding/WelcomeMobile.tsx:83 msgid "Choose the algorithms that power your experience with custom feeds." -msgstr "Choisissez les algorithmes qui alimentent votre expérience avec des fils d’actualité personnalisés." - -#: src/screens/Onboarding/StepAlgoFeeds/index.tsx:103 -#~ msgid "Choose your algorithmic feeds" -#~ msgstr "" +msgstr "Choisissez les algorithmes qui alimentent votre expérience avec des fils d’actu personnalisés." #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:103 msgid "Choose your main feeds" -msgstr "" +msgstr "Choisissez vos principaux fils d’actu" -#: src/view/com/auth/create/Step1.tsx:219 +#: src/view/com/auth/create/Step1.tsx:196 msgid "Choose your password" msgstr "Choisissez votre mot de passe" @@ -708,24 +658,27 @@ msgstr "Effacer la recherche" msgid "click here" msgstr "cliquez ici" -#: src/components/RichText.tsx:189 -#: src/components/TagMenu/index.web.tsx:125 +#: src/components/TagMenu/index.web.tsx:138 msgid "Click here to open tag menu for {tag}" -msgstr "" +msgstr "Cliquez ici pour ouvrir le menu de mot-clé pour {tag}" + +#: src/components/RichText.tsx:191 +msgid "Click here to open tag menu for #{tag}" +msgstr "Cliquez ici pour ouvrir le menu de mot-clé pour #{tag}" #: src/screens/Onboarding/index.tsx:35 msgid "Climate" -msgstr "" +msgstr "Climat" #: src/view/com/modals/ChangePassword.tsx:265 #: src/view/com/modals/ChangePassword.tsx:268 msgid "Close" -msgstr "" +msgstr "Fermer" -#: src/components/Dialog/index.web.tsx:80 -#: src/components/Dialog/index.web.tsx:194 +#: src/components/Dialog/index.web.tsx:84 +#: src/components/Dialog/index.web.tsx:198 msgid "Close active dialog" -msgstr "" +msgstr "Fermer le dialogue actif" #: src/view/com/auth/login/PasswordUpdatedForm.tsx:38 msgid "Close alert" @@ -747,9 +700,9 @@ msgstr "Fermer la visionneuse d’images" msgid "Close navigation footer" msgstr "Fermer le pied de page de navigation" -#: src/components/TagMenu/index.tsx:266 +#: src/components/TagMenu/index.tsx:262 msgid "Close this dialog" -msgstr "" +msgstr "Fermer ce dialogue" #: src/view/shell/index.web.tsx:52 msgid "Closes bottom navigation bar" @@ -767,34 +720,34 @@ msgstr "Ferme la fenêtre de rédaction et supprime le brouillon" msgid "Closes viewer for header image" msgstr "Ferme la visionneuse pour l’image d’en-tête" -#: src/view/com/notifications/FeedItem.tsx:317 +#: src/view/com/notifications/FeedItem.tsx:318 msgid "Collapses list of users for a given notification" msgstr "Réduit la liste des comptes pour une notification donnée" #: src/screens/Onboarding/index.tsx:41 msgid "Comedy" -msgstr "" +msgstr "Comédie" #: src/screens/Onboarding/index.tsx:27 msgid "Comics" -msgstr "" +msgstr "Bandes dessinées" -#: src/Navigation.tsx:227 +#: src/Navigation.tsx:229 #: src/view/screens/CommunityGuidelines.tsx:32 msgid "Community Guidelines" msgstr "Directives communautaires" #: src/screens/Onboarding/StepFinished.tsx:148 msgid "Complete onboarding and start using your account" -msgstr "" +msgstr "Terminez le didacticiel et commencez à utiliser votre compte" #: src/view/com/auth/create/Step3.tsx:73 msgid "Complete the challenge" -msgstr "" +msgstr "Compléter le défi" #: src/view/com/composer/Composer.tsx:424 msgid "Compose posts up to {MAX_GRAPHEME_LENGTH} characters in length" -msgstr "Permet d’écrire des messages de {MAX_GRAPHEME_LENGTH} caractères maximum" +msgstr "Permet d’écrire des posts de {MAX_GRAPHEME_LENGTH} caractères maximum" #: src/view/com/composer/Prompt.tsx:24 msgid "Compose reply" @@ -802,9 +755,9 @@ msgstr "Rédiger une réponse" #: src/screens/Onboarding/StepModeration/ModerationOption.tsx:67 msgid "Configure content filtering setting for category: {0}" -msgstr "" +msgstr "Configurer les paramètres de filtrage de contenu pour la catégorie : {0}" -#: src/components/Prompt.tsx:113 +#: src/components/Prompt.tsx:124 #: src/view/com/modals/AppealLabel.tsx:98 #: src/view/com/modals/SelfLabel.tsx:154 #: src/view/com/modals/VerifyEmail.tsx:231 @@ -843,10 +796,6 @@ msgstr "Confirmez votre âge pour activer le contenu pour adultes." msgid "Confirmation code" msgstr "Code de confirmation" -#: src/view/com/modals/Waitlist.tsx:120 -msgid "Confirms signing up {email} to the waitlist" -msgstr "Confirme l’inscription de {email} sur la liste d’attente" - #: src/view/com/auth/create/CreateAccount.tsx:193 #: src/view/com/auth/login/LoginForm.tsx:278 msgid "Connecting..." @@ -854,7 +803,7 @@ msgstr "Connexion…" #: src/view/com/auth/create/CreateAccount.tsx:213 msgid "Contact support" -msgstr "" +msgstr "Contacter le support" #: src/view/screens/Moderation.tsx:83 msgid "Content filtering" @@ -897,19 +846,19 @@ msgstr "Continuer" #: src/screens/Onboarding/StepModeration/index.tsx:115 #: src/screens/Onboarding/StepTopicalFeeds.tsx:111 msgid "Continue to next step" -msgstr "" +msgstr "Passer à l’étape suivante" #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:167 msgid "Continue to the next step" -msgstr "" +msgstr "Passer à l’étape suivante" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:191 msgid "Continue to the next step without following any accounts" -msgstr "" +msgstr "Passer à l’étape suivante sans suivre aucun compte" #: src/screens/Onboarding/index.tsx:44 msgid "Cooking" -msgstr "" +msgstr "Cuisine" #: src/view/com/modals/AddAppPasswords.tsx:195 #: src/view/com/modals/InviteCodes.tsx:182 @@ -922,7 +871,7 @@ msgstr "Version de build copiée dans le presse-papier" #: src/view/com/modals/AddAppPasswords.tsx:76 #: src/view/com/modals/InviteCodes.tsx:152 -#: src/view/com/util/forms/PostDropdownBtn.tsx:143 +#: src/view/com/util/forms/PostDropdownBtn.tsx:161 msgid "Copied to clipboard" msgstr "Copié dans le presse-papier" @@ -938,7 +887,8 @@ msgstr "Copie" msgid "Copy link to list" msgstr "Copier le lien vers la liste" -#: src/view/com/util/forms/PostDropdownBtn.tsx:184 +#: src/view/com/util/forms/PostDropdownBtn.tsx:231 +#: src/view/com/util/forms/PostDropdownBtn.tsx:237 msgid "Copy link to post" msgstr "Copier le lien vers le post" @@ -946,11 +896,12 @@ msgstr "Copier le lien vers le post" msgid "Copy link to profile" msgstr "Copier le lien vers le profil" -#: src/view/com/util/forms/PostDropdownBtn.tsx:170 +#: src/view/com/util/forms/PostDropdownBtn.tsx:223 +#: src/view/com/util/forms/PostDropdownBtn.tsx:225 msgid "Copy post text" msgstr "Copier le texte du post" -#: src/Navigation.tsx:232 +#: src/Navigation.tsx:234 #: src/view/screens/CopyrightPolicy.tsx:29 msgid "Copyright Policy" msgstr "Politique sur les droits d’auteur" @@ -959,14 +910,10 @@ msgstr "Politique sur les droits d’auteur" msgid "Could not load feed" msgstr "Impossible de charger le fil d’actu" -#: src/view/screens/ProfileList.tsx:888 +#: src/view/screens/ProfileList.tsx:893 msgid "Could not load list" msgstr "Impossible de charger la liste" -#: src/view/com/auth/create/Step2.tsx:91 -#~ msgid "Country" -#~ msgstr "" - #: src/view/com/auth/HomeLoggedOutCTA.tsx:62 #: src/view/com/auth/SplashScreen.tsx:71 #: src/view/com/auth/SplashScreen.web.tsx:81 @@ -1008,12 +955,12 @@ msgstr "Crée une carte avec une miniature. La carte pointe vers {url}" #: src/screens/Onboarding/index.tsx:29 msgid "Culture" -msgstr "" +msgstr "Culture" #: src/view/com/auth/server-input/index.tsx:95 #: src/view/com/auth/server-input/index.tsx:96 msgid "Custom" -msgstr "" +msgstr "Personnalisé" #: src/view/com/modals/ChangeHandle.tsx:389 msgid "Custom domain" @@ -1022,16 +969,12 @@ msgstr "Domaine personnalisé" #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:106 #: src/view/screens/Feeds.tsx:692 msgid "Custom feeds built by the community bring you new experiences and help you find the content you love." -msgstr "" +msgstr "Les fils d’actu personnalisés élaborés par la communauté vous font vivre de nouvelles expériences et vous aident à trouver le contenu que vous aimez." #: src/view/screens/PreferencesExternalEmbeds.tsx:55 msgid "Customize media from external sites." msgstr "Personnaliser les médias provenant de sites externes." -#: src/view/screens/Settings.tsx:687 -#~ msgid "Danger Zone" -#~ msgstr "Zone de danger" - #: src/view/screens/Settings/index.tsx:485 #: src/view/screens/Settings/index.tsx:511 msgid "Dark" @@ -1043,7 +986,7 @@ msgstr "Mode sombre" #: src/view/screens/Settings/index.tsx:498 msgid "Dark Theme" -msgstr "" +msgstr "Thème sombre" #: src/view/screens/Debug.tsx:83 msgid "Debug panel" @@ -1071,21 +1014,18 @@ msgstr "Supprimer la liste" msgid "Delete my account" msgstr "Supprimer mon compte" -#: src/view/screens/Settings.tsx:706 -#~ msgid "Delete my account…" -#~ msgstr "Supprimer mon compte…" - #: src/view/screens/Settings/index.tsx:784 msgid "Delete My Account…" -msgstr "" +msgstr "Supprimer mon compte…" -#: src/view/com/util/forms/PostDropdownBtn.tsx:273 +#: src/view/com/util/forms/PostDropdownBtn.tsx:317 +#: src/view/com/util/forms/PostDropdownBtn.tsx:326 msgid "Delete post" msgstr "Supprimer le post" -#: src/view/com/util/forms/PostDropdownBtn.tsx:277 +#: src/view/com/util/forms/PostDropdownBtn.tsx:321 msgid "Delete this post?" -msgstr "Supprimer ce post ?" +msgstr "Supprimer ce post ?" #: src/view/com/util/post-embeds/QuoteEmbed.tsx:70 msgid "Deleted" @@ -1102,17 +1042,13 @@ msgstr "Post supprimé." msgid "Description" msgstr "Description" -#: src/view/screens/Settings.tsx:760 -#~ msgid "Developer Tools" -#~ msgstr "Outils de dév" - #: src/view/com/composer/Composer.tsx:218 msgid "Did you want to say anything?" -msgstr "Vous vouliez dire quelque chose ?" +msgstr "Vous vouliez dire quelque chose ?" #: src/view/screens/Settings/index.tsx:504 msgid "Dim" -msgstr "" +msgstr "Atténué" #: src/view/com/composer/Composer.tsx:151 msgid "Discard" @@ -1131,13 +1067,9 @@ msgstr "Empêcher les applis de montrer mon compte aux personnes non connectées msgid "Discover new custom feeds" msgstr "Découvrir des fils d’actu personnalisés" -#: src/view/screens/Feeds.tsx:473 -#~ msgid "Discover new feeds" -#~ msgstr "Découvrir de nouveaux fils d’actu" - #: src/view/screens/Feeds.tsx:689 msgid "Discover New Feeds" -msgstr "" +msgstr "Découvrir de nouveaux fils d’actu" #: src/view/com/modals/EditProfile.tsx:192 msgid "Display name" @@ -1149,11 +1081,7 @@ msgstr "Afficher le nom" #: src/view/com/modals/ChangeHandle.tsx:487 msgid "Domain verified!" -msgstr "Domaine vérifié !" - -#: src/view/com/auth/create/Step1.tsx:170 -msgid "Don't have an invite code?" -msgstr "Pas de code d’invitation ?" +msgstr "Domaine vérifié !" #: src/view/com/auth/onboarding/RecommendedFollows.tsx:86 #: src/view/com/modals/EditImage.tsx:333 @@ -1194,20 +1122,20 @@ msgstr "Tapotez deux fois pour vous connecter" #: src/view/screens/Settings/index.tsx:755 msgid "Download Bluesky account data (repository)" -msgstr "" +msgstr "Télécharger les données du compte Bluesky (dépôt)" #: src/view/screens/Settings/ExportCarDialog.tsx:59 #: src/view/screens/Settings/ExportCarDialog.tsx:63 msgid "Download CAR file" -msgstr "" +msgstr "Télécharger le fichier CAR" #: src/view/com/composer/text-input/TextInput.web.tsx:249 msgid "Drop to add images" -msgstr "" +msgstr "Déposer pour ajouter des images" #: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:111 msgid "Due to Apple policies, adult content can only be enabled on the web after completing sign up." -msgstr "" +msgstr "En raison des politiques d’Apple, le contenu pour adultes ne peut être activé que via le Web une fois l’inscription terminée." #: src/view/com/modals/EditProfile.tsx:185 msgid "e.g. Alice Roberts" @@ -1255,7 +1183,7 @@ msgstr "Modifier les infos de la liste" msgid "Edit Moderation List" msgstr "Modifier la liste de modération" -#: src/Navigation.tsx:242 +#: src/Navigation.tsx:244 #: src/view/screens/Feeds.tsx:434 #: src/view/screens/SavedFeeds.tsx:84 msgid "Edit My Feeds" @@ -1273,7 +1201,7 @@ msgstr "Modifier le profil" msgid "Edit Profile" msgstr "Modifier le profil" -#: src/view/com/home/HomeHeaderLayout.web.tsx:59 +#: src/view/com/home/HomeHeaderLayout.web.tsx:62 #: src/view/screens/Feeds.tsx:355 msgid "Edit Saved Feeds" msgstr "Modifier les fils d’actu enregistrés" @@ -1292,16 +1220,15 @@ msgstr "Modifier votre description de profil" #: src/screens/Onboarding/index.tsx:34 msgid "Education" -msgstr "" +msgstr "Éducation" -#: src/view/com/auth/create/Step1.tsx:199 +#: src/view/com/auth/create/Step1.tsx:176 #: src/view/com/auth/login/ForgotPasswordForm.tsx:156 #: src/view/com/modals/ChangeEmail.tsx:141 -#: src/view/com/modals/Waitlist.tsx:88 msgid "Email" msgstr "E-mail" -#: src/view/com/auth/create/Step1.tsx:190 +#: src/view/com/auth/create/Step1.tsx:167 #: src/view/com/auth/login/ForgotPasswordForm.tsx:147 msgid "Email address" msgstr "Adresse e-mail" @@ -1321,7 +1248,7 @@ msgstr "Adresse e-mail vérifiée" #: src/view/screens/Settings/index.tsx:312 msgid "Email:" -msgstr "E-mail :" +msgstr "E-mail :" #: src/view/com/modals/EmbedConsent.tsx:113 msgid "Enable {0} only" @@ -1334,7 +1261,7 @@ msgstr "Activer le contenu pour adultes" #: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:76 #: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:77 msgid "Enable adult content in your feeds" -msgstr "" +msgstr "Activer le contenu pour adultes dans vos fils d’actu" #: src/view/com/modals/EmbedConsent.tsx:97 msgid "Enable External Media" @@ -1356,10 +1283,10 @@ msgstr "Fin du fil d’actu" msgid "Enter a name for this App Password" msgstr "Entrer un nom pour ce mot de passe d’application" -#: src/components/dialogs/MutedWords.tsx:87 -#: src/components/dialogs/MutedWords.tsx:88 +#: src/components/dialogs/MutedWords.tsx:100 +#: src/components/dialogs/MutedWords.tsx:101 msgid "Enter a word or tag" -msgstr "" +msgstr "Saisir un mot ou un mot-clé" #: src/view/com/modals/VerifyEmail.tsx:105 msgid "Enter Confirmation Code" @@ -1367,7 +1294,7 @@ msgstr "Entrer un code de confirmation" #: src/view/com/modals/ChangePassword.tsx:151 msgid "Enter the code you received to change your password." -msgstr "" +msgstr "Saisissez le code que vous avez reçu pour modifier votre mot de passe." #: src/view/com/modals/ChangeHandle.tsx:371 msgid "Enter the domain you want to use" @@ -1375,18 +1302,14 @@ msgstr "Entrez le domaine que vous voulez utiliser" #: src/view/com/auth/login/ForgotPasswordForm.tsx:107 msgid "Enter the email you used to create your account. We'll send you a \"reset code\" so you can set a new password." -msgstr "Saisissez l’e-mail que vous avez utilisé pour créer votre compte. Nous vous enverrons un « code de réinitialisation » afin changer votre mot de passe." +msgstr "Saisissez l’e-mail que vous avez utilisé pour créer votre compte. Nous vous enverrons un « code de réinitialisation » afin changer votre mot de passe." -#: src/view/com/auth/create/Step1.tsx:251 +#: src/view/com/auth/create/Step1.tsx:228 #: src/view/com/modals/BirthDateSettings.tsx:74 msgid "Enter your birth date" msgstr "Saisissez votre date de naissance" -#: src/view/com/modals/Waitlist.tsx:78 -msgid "Enter your email" -msgstr "Entrez votre e-mail" - -#: src/view/com/auth/create/Step1.tsx:195 +#: src/view/com/auth/create/Step1.tsx:172 msgid "Enter your email address" msgstr "Entrez votre e-mail" @@ -1398,21 +1321,17 @@ msgstr "Entrez votre nouvel e-mail ci-dessus" msgid "Enter your new email address below." msgstr "Entrez votre nouvelle e-mail ci-dessous." -#: src/view/com/auth/create/Step2.tsx:188 -#~ msgid "Enter your phone number" -#~ msgstr "" - #: src/view/com/auth/login/Login.tsx:99 msgid "Enter your username and password" msgstr "Entrez votre pseudo et votre mot de passe" #: src/view/com/auth/create/Step3.tsx:67 msgid "Error receiving captcha response." -msgstr "" +msgstr "Erreur de réception de la réponse captcha." #: src/view/screens/Search/Search.tsx:110 msgid "Error:" -msgstr "Erreur :" +msgstr "Erreur :" #: src/view/com/modals/Threadgate.tsx:76 msgid "Everybody" @@ -1431,10 +1350,6 @@ msgstr "Sort de la vue de l’image" msgid "Exits inputting search query" msgstr "Sort de la saisie de la recherche" -#: src/view/com/modals/Waitlist.tsx:138 -msgid "Exits signing up for waitlist with {email}" -msgstr "Sort de l’inscription sur la liste d’attente avec {email}" - #: src/view/com/lightbox/Lightbox.web.tsx:163 msgid "Expand alt text" msgstr "Développer le texte alt" @@ -1446,12 +1361,12 @@ msgstr "Développe ou réduit le post complet auquel vous répondez" #: src/view/screens/Settings/index.tsx:753 msgid "Export my data" -msgstr "" +msgstr "Exporter mes données" #: src/view/screens/Settings/ExportCarDialog.tsx:44 #: src/view/screens/Settings/index.tsx:764 msgid "Export My Data" -msgstr "" +msgstr "Exporter mes données" #: src/view/com/modals/EmbedConsent.tsx:64 msgid "External Media" @@ -1462,7 +1377,7 @@ msgstr "Média externe" msgid "External media may allow websites to collect information about you and your device. No information is sent or requested until you press the \"play\" button." msgstr "Les médias externes peuvent permettre à des sites web de collecter des informations sur vous et votre appareil. Aucune information n’est envoyée ou demandée tant que vous n’appuyez pas sur le bouton de lecture." -#: src/Navigation.tsx:261 +#: src/Navigation.tsx:263 #: src/view/screens/PreferencesExternalEmbeds.tsx:52 #: src/view/screens/Settings/index.tsx:657 msgid "External Media Preferences" @@ -1481,7 +1396,7 @@ msgstr "Échec de la création du mot de passe d’application." msgid "Failed to create the list. Check your internet connection and try again." msgstr "Échec de la création de la liste. Vérifiez votre connexion Internet et réessayez." -#: src/view/com/util/forms/PostDropdownBtn.tsx:110 +#: src/view/com/util/forms/PostDropdownBtn.tsx:128 msgid "Failed to delete post, please try again" msgstr "Échec de la suppression du post, veuillez réessayer" @@ -1490,7 +1405,7 @@ msgstr "Échec de la suppression du post, veuillez réessayer" msgid "Failed to load recommended feeds" msgstr "Échec du chargement des fils d’actu recommandés" -#: src/Navigation.tsx:192 +#: src/Navigation.tsx:194 msgid "Feed" msgstr "Fil d’actu" @@ -1502,16 +1417,12 @@ msgstr "Fil d’actu par {0}" msgid "Feed offline" msgstr "Fil d’actu hors ligne" -#: src/view/com/feeds/FeedPage.tsx:143 -#~ msgid "Feed Preferences" -#~ msgstr "Préférences en matière de fil d’actu" - #: src/view/shell/desktop/RightNav.tsx:61 #: src/view/shell/Drawer.tsx:311 msgid "Feedback" msgstr "Feedback" -#: src/Navigation.tsx:445 +#: src/Navigation.tsx:452 #: src/view/screens/Feeds.tsx:419 #: src/view/screens/Feeds.tsx:524 #: src/view/screens/Profile.tsx:184 @@ -1520,15 +1431,7 @@ msgstr "Feedback" #: src/view/shell/Drawer.tsx:476 #: src/view/shell/Drawer.tsx:477 msgid "Feeds" -msgstr "Fil d’actu" - -#: src/screens/Onboarding/StepAlgoFeeds/index.tsx:106 -#~ msgid "Feeds are created by users and can give you entirely new experiences." -#~ msgstr "" - -#: src/screens/Onboarding/StepAlgoFeeds/index.tsx:106 -#~ msgid "Feeds are created by users and organizations. They offer you varied experiences and suggest content you may like using algorithms." -#~ msgstr "" +msgstr "Fils d’actu" #: src/view/com/auth/onboarding/RecommendedFeeds.tsx:57 msgid "Feeds are created by users to curate content. Choose some feeds that you find interesting." @@ -1540,11 +1443,11 @@ msgstr "Les fils d’actu sont des algorithmes personnalisés qui se construisen #: src/screens/Onboarding/StepTopicalFeeds.tsx:76 msgid "Feeds can be topical as well!" -msgstr "" +msgstr "Les fils d’actu peuvent également être thématiques !" #: src/screens/Onboarding/StepFinished.tsx:151 msgid "Finalizing" -msgstr "" +msgstr "Finalisation" #: src/view/com/posts/CustomFeedEmptyState.tsx:47 #: src/view/com/posts/FollowingEmptyState.tsx:57 @@ -1566,11 +1469,7 @@ msgstr "Recherche de comptes similaires…" #: src/view/screens/PreferencesFollowingFeed.tsx:111 msgid "Fine-tune the content you see on your Following feed." -msgstr "" - -#: src/view/screens/PreferencesHomeFeed.tsx:111 -#~ msgid "Fine-tune the content you see on your home screen." -#~ msgstr "Affine le contenu affiché sur votre écran d’accueil." +msgstr "Affine le contenu affiché sur votre fil d’actu « Following »." #: src/view/screens/PreferencesThreads.tsx:60 msgid "Fine-tune the discussion threads." @@ -1578,11 +1477,11 @@ msgstr "Affine les fils de discussion." #: src/screens/Onboarding/index.tsx:38 msgid "Fitness" -msgstr "" +msgstr "Fitness" #: src/screens/Onboarding/StepFinished.tsx:131 msgid "Flexible" -msgstr "" +msgstr "Flexible" #: src/view/com/modals/EditImage.tsx:115 msgid "Flip horizontal" @@ -1612,11 +1511,11 @@ msgstr "Suivre {0}" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:179 msgid "Follow All" -msgstr "" +msgstr "Suivre tous" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:174 msgid "Follow selected accounts and continue to the next step" -msgstr "" +msgstr "Suivre les comptes sélectionnés et passer à l’étape suivante" #: src/view/com/auth/onboarding/RecommendedFollows.tsx:64 msgid "Follow some users to get started. We can recommend you more users based on who you find interesting." @@ -1652,13 +1551,13 @@ msgstr "Suivi" msgid "Following {0}" msgstr "Suit {0}" -#: src/Navigation.tsx:248 -#: src/view/com/home/HomeHeaderLayout.web.tsx:45 -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:83 +#: src/Navigation.tsx:250 +#: src/view/com/home/HomeHeaderLayout.web.tsx:50 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:84 #: src/view/screens/PreferencesFollowingFeed.tsx:104 #: src/view/screens/Settings/index.tsx:543 msgid "Following Feed Preferences" -msgstr "" +msgstr "Préférences en matière de fil d’actu « Following »" #: src/view/com/profile/ProfileHeader.tsx:546 msgid "Follows you" @@ -1670,7 +1569,7 @@ msgstr "Vous suit" #: src/screens/Onboarding/index.tsx:43 msgid "Food" -msgstr "" +msgstr "Nourriture" #: src/view/com/modals/DeleteAccount.tsx:111 msgid "For security reasons, we'll need to send a confirmation code to your email address." @@ -1693,6 +1592,11 @@ msgstr "Mot de passe oublié" msgid "Forgot Password" msgstr "Mot de passe oublié" +#: src/screens/Hashtag.tsx:108 +#: src/screens/Hashtag.tsx:148 +msgid "From @{sanitizedAuthor}" +msgstr "De @{sanitizedAuthor}" + #: src/view/com/posts/FeedItem.tsx:189 msgctxt "from-feed" msgid "From <0/>" @@ -1716,20 +1620,20 @@ msgstr "Retour" #: src/view/screens/ProfileFeed.tsx:106 #: src/view/screens/ProfileFeed.tsx:111 -#: src/view/screens/ProfileList.tsx:897 #: src/view/screens/ProfileList.tsx:902 +#: src/view/screens/ProfileList.tsx:907 msgid "Go Back" msgstr "Retour" #: src/screens/Onboarding/Layout.tsx:104 #: src/screens/Onboarding/Layout.tsx:193 msgid "Go back to previous step" -msgstr "" +msgstr "Retour à l’étape précédente" #: src/view/screens/Search/Search.tsx:747 #: src/view/shell/desktop/Search.tsx:262 msgid "Go to @{queryMaybeHandle}" -msgstr "" +msgstr "Aller à @{queryMaybeHandle}" #: src/view/com/auth/login/ForgotPasswordForm.tsx:189 #: src/view/com/auth/login/ForgotPasswordForm.tsx:218 @@ -1743,13 +1647,17 @@ msgstr "Aller à la suite" msgid "Handle" msgstr "Pseudo" -#: src/components/RichText.tsx:188 -msgid "Hashtag: {tag}" -msgstr "" +#: src/Navigation.tsx:270 +msgid "Hashtag" +msgstr "Mot-clé" + +#: src/components/RichText.tsx:190 +msgid "Hashtag: #{tag}" +msgstr "Mot-clé : #{tag}" #: src/view/com/auth/create/CreateAccount.tsx:208 msgid "Having trouble?" -msgstr "" +msgstr "Un souci ?" #: src/view/shell/desktop/RightNav.tsx:90 #: src/view/shell/Drawer.tsx:321 @@ -1758,15 +1666,15 @@ msgstr "Aide" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:132 msgid "Here are some accounts for you to follow" -msgstr "" +msgstr "Voici quelques comptes à suivre" #: src/screens/Onboarding/StepTopicalFeeds.tsx:85 msgid "Here are some popular topical feeds. You can choose to follow as many as you like." -msgstr "" +msgstr "Voici quelques fils d’actu thématiques populaires. Vous pouvez choisir d’en suivre autant que vous le souhaitez." #: src/screens/Onboarding/StepTopicalFeeds.tsx:80 msgid "Here are some topical feeds based on your interests: {interestsText}. You can choose to follow as many as you like." -msgstr "" +msgstr "Voici quelques fils d’actu thématiques basés sur vos centres d’intérêt : {interestsText}. Vous pouvez choisir d’en suivre autant que vous le souhaitez." #: src/view/com/modals/AddAppPasswords.tsx:153 msgid "Here is your app password." @@ -1780,12 +1688,13 @@ msgid "Hide" msgstr "Cacher" #: src/view/com/modals/ContentFilteringSettings.tsx:224 -#: src/view/com/notifications/FeedItem.tsx:325 +#: src/view/com/notifications/FeedItem.tsx:326 msgctxt "action" msgid "Hide" msgstr "Cacher" -#: src/view/com/util/forms/PostDropdownBtn.tsx:232 +#: src/view/com/util/forms/PostDropdownBtn.tsx:276 +#: src/view/com/util/forms/PostDropdownBtn.tsx:287 msgid "Hide post" msgstr "Cacher ce post" @@ -1794,11 +1703,11 @@ msgstr "Cacher ce post" msgid "Hide the content" msgstr "Cacher ce contenu" -#: src/view/com/util/forms/PostDropdownBtn.tsx:236 +#: src/view/com/util/forms/PostDropdownBtn.tsx:280 msgid "Hide this post?" -msgstr "Cacher ce post ?" +msgstr "Cacher ce post ?" -#: src/view/com/notifications/FeedItem.tsx:315 +#: src/view/com/notifications/FeedItem.tsx:316 msgid "Hide user list" msgstr "Cacher la liste des comptes" @@ -1826,7 +1735,7 @@ msgstr "Mmm… le serveur de fils d’actu ne répond pas. Veuillez informer la msgid "Hmm, we're having trouble finding this feed. It may have been deleted." msgstr "Hmm, nous n’arrivons pas à trouver ce fil d’actu. Il a peut-être été supprimé." -#: src/Navigation.tsx:435 +#: src/Navigation.tsx:442 #: src/view/shell/bottom-bar/BottomBar.tsx:137 #: src/view/shell/desktop/LeftNav.tsx:306 #: src/view/shell/Drawer.tsx:398 @@ -1834,21 +1743,14 @@ msgstr "Hmm, nous n’arrivons pas à trouver ce fil d’actu. Il a peut-être à msgid "Home" msgstr "Accueil" -#: src/Navigation.tsx:247 -#: src/view/com/pager/FeedsTabBarMobile.tsx:123 -#: src/view/screens/PreferencesHomeFeed.tsx:104 -#: src/view/screens/Settings/index.tsx:543 -#~ msgid "Home Feed Preferences" -#~ msgstr "Préférences de fils d’actu de l’accueil" - -#: src/view/com/auth/create/Step1.tsx:82 +#: src/view/com/auth/create/Step1.tsx:75 #: src/view/com/auth/login/ForgotPasswordForm.tsx:120 msgid "Hosting provider" msgstr "Hébergeur" #: src/view/com/modals/InAppBrowserConsent.tsx:44 msgid "How should we open this link?" -msgstr "" +msgstr "Comment ouvrir ce lien ?" #: src/view/com/modals/VerifyEmail.tsx:214 msgid "I have a code" @@ -1872,7 +1774,7 @@ msgstr "Si rien n’est sélectionné, il n’y a pas de restriction d’âge." #: src/view/com/modals/ChangePassword.tsx:146 msgid "If you want to change your password, we will send you a code to verify that this is your account." -msgstr "" +msgstr "Si vous souhaitez modifier votre mot de passe, nous vous enverrons un code pour vérifier qu’il s’agit bien de votre compte." #: src/view/com/util/images/Gallery.tsx:38 msgid "Image" @@ -1895,11 +1797,11 @@ msgstr "Entrez le code envoyé à votre e-mail pour réinitialiser le mot de pas msgid "Input confirmation code for account deletion" msgstr "Entrez le code de confirmation pour supprimer le compte" -#: src/view/com/auth/create/Step1.tsx:200 +#: src/view/com/auth/create/Step1.tsx:177 msgid "Input email for Bluesky account" -msgstr "" +msgstr "Saisir l’email pour le compte Bluesky" -#: src/view/com/auth/create/Step1.tsx:158 +#: src/view/com/auth/create/Step1.tsx:151 msgid "Input invite code to proceed" msgstr "Entrez le code d’invitation pour continuer" @@ -1915,10 +1817,6 @@ msgstr "Entrez le nouveau mot de passe" msgid "Input password for account deletion" msgstr "Entrez le mot de passe pour la suppression du compte" -#: src/view/com/auth/create/Step2.tsx:196 -#~ msgid "Input phone number for SMS verification" -#~ msgstr "" - #: src/view/com/auth/login/LoginForm.tsx:230 msgid "Input the password tied to {identifier}" msgstr "Entrez le mot de passe associé à {identifier}" @@ -1927,14 +1825,6 @@ msgstr "Entrez le mot de passe associé à {identifier}" msgid "Input the username or email address you used at signup" msgstr "Entrez le pseudo ou l’adresse e-mail que vous avez utilisé lors de l’inscription" -#: src/view/com/auth/create/Step2.tsx:271 -#~ msgid "Input the verification code we have texted to you" -#~ msgstr "" - -#: src/view/com/modals/Waitlist.tsx:90 -msgid "Input your email to get on the Bluesky waitlist" -msgstr "Entrez votre e-mail pour vous inscrire sur la liste d’attente de Bluesky" - #: src/view/com/auth/login/LoginForm.tsx:229 msgid "Input your password" msgstr "Entrez votre mot de passe" @@ -1951,16 +1841,12 @@ msgstr "Enregistrement de post invalide ou non pris en charge" msgid "Invalid username or password" msgstr "Pseudo ou mot de passe incorrect" -#: src/view/screens/Settings.tsx:411 -#~ msgid "Invite" -#~ msgstr "Inviter" - #: src/view/com/modals/InviteCodes.tsx:93 msgid "Invite a Friend" msgstr "Inviter un ami" -#: src/view/com/auth/create/Step1.tsx:148 -#: src/view/com/auth/create/Step1.tsx:157 +#: src/view/com/auth/create/Step1.tsx:141 +#: src/view/com/auth/create/Step1.tsx:150 msgid "Invite code" msgstr "Code d’invitation" @@ -1970,41 +1856,24 @@ msgstr "Code d’invitation refusé. Vérifiez que vous l’avez saisi correctem #: src/view/com/modals/InviteCodes.tsx:170 msgid "Invite codes: {0} available" -msgstr "Code d’invitation : {0} disponible" - -#: src/view/shell/Drawer.tsx:645 -#~ msgid "Invite codes: {invitesAvailable} available" -#~ msgstr "Invitations : {invitesAvailable} codes dispo" +msgstr "Code d’invitation : {0} disponible" #: src/view/com/modals/InviteCodes.tsx:169 msgid "Invite codes: 1 available" -msgstr "Invitations : 1 code dispo" +msgstr "Invitations : 1 code dispo" #: src/screens/Onboarding/StepFollowingFeed.tsx:64 msgid "It shows posts from the people you follow as they happen." -msgstr "" +msgstr "Il affiche les posts des personnes que vous suivez au fur et à mesure qu’ils sont publiés." #: src/view/com/auth/HomeLoggedOutCTA.tsx:99 #: src/view/com/auth/SplashScreen.web.tsx:138 msgid "Jobs" msgstr "Emplois" -#: src/view/com/modals/Waitlist.tsx:67 -msgid "Join the waitlist" -msgstr "S’inscrire sur la liste d’attente" - -#: src/view/com/auth/create/Step1.tsx:174 -#: src/view/com/auth/create/Step1.tsx:178 -msgid "Join the waitlist." -msgstr "S’inscrire sur la liste d’attente." - -#: src/view/com/modals/Waitlist.tsx:128 -msgid "Join Waitlist" -msgstr "S’inscrire sur la liste d’attente" - #: src/screens/Onboarding/index.tsx:24 msgid "Journalism" -msgstr "" +msgstr "Journalisme" #: src/view/com/composer/select-language/SelectLangBtn.tsx:104 msgid "Language selection" @@ -2014,7 +1883,7 @@ msgstr "Sélection de la langue" msgid "Language settings" msgstr "Préférences de langue" -#: src/Navigation.tsx:140 +#: src/Navigation.tsx:142 #: src/view/screens/LanguageSettings.tsx:89 msgid "Language Settings" msgstr "Paramètres linguistiques" @@ -2025,7 +1894,7 @@ msgstr "Langues" #: src/view/com/auth/create/StepHeader.tsx:20 msgid "Last step!" -msgstr "Dernière étape !" +msgstr "Dernière étape !" #: src/view/com/util/moderation/ContentHider.tsx:103 msgid "Learn more" @@ -2059,7 +1928,7 @@ msgstr "Quitter Bluesky" #: src/screens/Deactivated.tsx:128 msgid "left to go." -msgstr "" +msgstr "devant vous dans la file." #: src/view/screens/Settings/index.tsx:278 msgid "Legacy storage cleared, you need to restart the app now." @@ -2068,11 +1937,11 @@ msgstr "Stockage ancien effacé, vous devez redémarrer l’application maintena #: src/view/com/auth/login/Login.tsx:128 #: src/view/com/auth/login/Login.tsx:144 msgid "Let's get your password reset!" -msgstr "Réinitialisez votre mot de passe !" +msgstr "Réinitialisez votre mot de passe !" #: src/screens/Onboarding/StepFinished.tsx:151 msgid "Let's go!" -msgstr "" +msgstr "Allons-y !" #: src/view/com/util/UserAvatar.tsx:248 #: src/view/com/util/UserBanner.tsx:62 @@ -2084,7 +1953,6 @@ msgid "Light" msgstr "Clair" #: src/view/com/util/post-ctrls/PostCtrls.tsx:182 -#: src/view/com/util/post-ctrls/PostCtrls.tsx:216 msgid "Like" msgstr "Liker" @@ -2092,14 +1960,14 @@ msgstr "Liker" msgid "Like this feed" msgstr "Liker ce fil d’actu" -#: src/Navigation.tsx:197 +#: src/Navigation.tsx:199 msgid "Liked by" msgstr "Liké par" #: src/view/screens/PostLikedBy.tsx:27 #: src/view/screens/ProfileFeedLikedBy.tsx:27 msgid "Liked By" -msgstr "" +msgstr "Liké par" #: src/view/com/feeds/FeedSourceCard.tsx:279 msgid "Liked by {0} {1}" @@ -2125,7 +1993,7 @@ msgstr "Likes" msgid "Likes on this post" msgstr "Likes sur ce post" -#: src/Navigation.tsx:166 +#: src/Navigation.tsx:168 msgid "List" msgstr "Liste" @@ -2161,7 +2029,7 @@ msgstr "Liste débloquée" msgid "List unmuted" msgstr "Liste démasquée" -#: src/Navigation.tsx:110 +#: src/Navigation.tsx:112 #: src/view/screens/Profile.tsx:185 #: src/view/shell/desktop/LeftNav.tsx:379 #: src/view/shell/Drawer.tsx:492 @@ -2172,7 +2040,7 @@ msgstr "Listes" #: src/view/com/post-thread/PostThread.tsx:333 #: src/view/com/post-thread/PostThread.tsx:341 msgid "Load more posts" -msgstr "Charger plus d’articles" +msgstr "Charger plus de posts" #: src/view/screens/Notifications.tsx:159 msgid "Load new notifications" @@ -2183,17 +2051,13 @@ msgstr "Charger les nouvelles notifications" #: src/view/screens/ProfileFeed.tsx:495 #: src/view/screens/ProfileList.tsx:681 msgid "Load new posts" -msgstr "Charger les nouveaux messages" +msgstr "Charger les nouveaux posts" #: src/view/com/composer/text-input/mobile/Autocomplete.tsx:95 msgid "Loading..." msgstr "Chargement…" -#: src/view/com/modals/ServerInput.tsx:50 -#~ msgid "Local dev server" -#~ msgstr "Serveur de dév local" - -#: src/Navigation.tsx:207 +#: src/Navigation.tsx:209 msgid "Log" msgstr "Journaux" @@ -2202,7 +2066,7 @@ msgstr "Journaux" #: src/screens/Deactivated.tsx:178 #: src/screens/Deactivated.tsx:181 msgid "Log out" -msgstr "" +msgstr "Déconnexion" #: src/view/screens/Moderation.tsx:155 msgid "Logged-out visibility" @@ -2214,19 +2078,19 @@ msgstr "Se connecter à un compte qui n’est pas listé" #: src/view/com/modals/LinkWarning.tsx:65 msgid "Make sure this is where you intend to go!" -msgstr "Assurez-vous que c’est bien là que vous avez l’intention d’aller !" +msgstr "Assurez-vous que c’est bien là que vous avez l’intention d’aller !" -#: src/components/dialogs/MutedWords.tsx:71 +#: src/components/dialogs/MutedWords.tsx:83 msgid "Manage your muted words and tags" -msgstr "" +msgstr "Gérer les mots et les mots-clés masqués" #: src/view/com/auth/create/Step2.tsx:118 msgid "May not be longer than 253 characters" -msgstr "" +msgstr "Ne doit pas dépasser 253 caractères" #: src/view/com/auth/create/Step2.tsx:109 msgid "May only contain letters and numbers" -msgstr "" +msgstr "Ne peut contenir que des lettres et des chiffres" #: src/view/screens/Profile.tsx:182 msgid "Media" @@ -2240,16 +2104,16 @@ msgstr "comptes mentionnés" msgid "Mentioned users" msgstr "Comptes mentionnés" -#: src/view/com/util/ViewHeader.tsx:81 +#: src/view/com/util/ViewHeader.tsx:87 #: src/view/screens/Search/Search.tsx:646 msgid "Menu" msgstr "Menu" #: src/view/com/posts/FeedErrorMessage.tsx:197 msgid "Message from server: {0}" -msgstr "Message du serveur : {0}" +msgstr "Message du serveur : {0}" -#: src/Navigation.tsx:115 +#: src/Navigation.tsx:117 #: src/view/screens/Moderation.tsx:66 #: src/view/screens/Settings/index.tsx:625 #: src/view/shell/desktop/LeftNav.tsx:397 @@ -2263,13 +2127,13 @@ msgstr "Modération" msgid "Moderation list by {0}" msgstr "Liste de modération par {0}" -#: src/view/screens/ProfileList.tsx:774 +#: src/view/screens/ProfileList.tsx:775 msgid "Moderation list by <0/>" msgstr "Liste de modération par <0/>" #: src/view/com/lists/ListCard.tsx:91 #: src/view/com/modals/UserAddRemoveLists.tsx:204 -#: src/view/screens/ProfileList.tsx:772 +#: src/view/screens/ProfileList.tsx:773 msgid "Moderation list by you" msgstr "Liste de modération par vous" @@ -2285,7 +2149,7 @@ msgstr "Liste de modération mise à jour" msgid "Moderation lists" msgstr "Listes de modération" -#: src/Navigation.tsx:120 +#: src/Navigation.tsx:122 #: src/view/screens/ModerationModlists.tsx:58 msgid "Moderation Lists" msgstr "Listes de modération" @@ -2298,7 +2162,7 @@ msgstr "Paramètres de modération" msgid "Moderator has chosen to set a general warning on the content." msgstr "La modération a choisi d’ajouter un avertissement général sur le contenu." -#: src/view/shell/desktop/Feeds.tsx:63 +#: src/view/shell/desktop/Feeds.tsx:65 msgid "More feeds" msgstr "Plus de fils d’actu" @@ -2308,25 +2172,21 @@ msgstr "Plus de fils d’actu" msgid "More options" msgstr "Plus d’options" -#: src/view/com/util/forms/PostDropdownBtn.tsx:315 -msgid "More post options" -msgstr "Plus d’options de post" - #: src/view/screens/PreferencesThreads.tsx:82 msgid "Most-liked replies first" msgstr "Réponses les plus likées en premier" #: src/view/com/auth/create/Step2.tsx:122 msgid "Must be at least 3 characters" -msgstr "" +msgstr "Doit comporter au moins 3 caractères" -#: src/components/TagMenu/index.tsx:253 +#: src/components/TagMenu/index.tsx:249 msgid "Mute" -msgstr "" +msgstr "Masquer" -#: src/components/TagMenu/index.web.tsx:91 +#: src/components/TagMenu/index.web.tsx:105 msgid "Mute {truncatedTag}" -msgstr "" +msgstr "Masquer {truncatedTag}" #: src/view/com/profile/ProfileHeader.tsx:327 msgid "Mute Account" @@ -2336,17 +2196,17 @@ msgstr "Masquer le compte" msgid "Mute accounts" msgstr "Masquer les comptes" -#: src/components/TagMenu/index.tsx:211 -msgid "Mute all {tag} posts" -msgstr "" +#: src/components/TagMenu/index.tsx:209 +msgid "Mute all {displayTag} posts" +msgstr "Masquer tous les posts {displayTag}" -#: src/components/dialogs/MutedWords.tsx:131 +#: src/components/dialogs/MutedWords.tsx:149 msgid "Mute in tags only" -msgstr "" +msgstr "Masquer dans les mots-clés uniquement" -#: src/components/dialogs/MutedWords.tsx:116 +#: src/components/dialogs/MutedWords.tsx:134 msgid "Mute in text & tags" -msgstr "" +msgstr "Masquer dans le texte et les mots-clés" #: src/view/screens/ProfileList.tsx:491 msgid "Mute list" @@ -2354,48 +2214,50 @@ msgstr "Masquer la liste" #: src/view/screens/ProfileList.tsx:275 msgid "Mute these accounts?" -msgstr "Masquer ces comptes ?" +msgstr "Masquer ces comptes ?" #: src/view/screens/ProfileList.tsx:279 msgid "Mute this List" msgstr "Masquer cette liste" -#: src/components/dialogs/MutedWords.tsx:109 +#: src/components/dialogs/MutedWords.tsx:127 msgid "Mute this word in post text and tags" -msgstr "" +msgstr "Masquer ce mot dans le texte du post et les mots-clés" -#: src/components/dialogs/MutedWords.tsx:124 +#: src/components/dialogs/MutedWords.tsx:142 msgid "Mute this word in tags only" -msgstr "" +msgstr "Masquer ce mot dans les mots-clés uniquement" -#: src/view/com/util/forms/PostDropdownBtn.tsx:202 +#: src/view/com/util/forms/PostDropdownBtn.tsx:251 +#: src/view/com/util/forms/PostDropdownBtn.tsx:257 msgid "Mute thread" msgstr "Masquer ce fil de discussion" -#: src/view/com/util/forms/PostDropdownBtn.tsx:216 +#: src/view/com/util/forms/PostDropdownBtn.tsx:267 +#: src/view/com/util/forms/PostDropdownBtn.tsx:269 msgid "Mute words & tags" -msgstr "" +msgstr "Masquer les mots et les mots-clés" #: src/view/com/lists/ListCard.tsx:102 msgid "Muted" -msgstr "" +msgstr "Masqué" #: src/view/screens/Moderation.tsx:128 msgid "Muted accounts" msgstr "Comptes masqués" -#: src/Navigation.tsx:125 +#: src/Navigation.tsx:127 #: src/view/screens/ModerationMutedAccounts.tsx:107 msgid "Muted Accounts" msgstr "Comptes masqués" #: src/view/screens/ModerationMutedAccounts.tsx:115 msgid "Muted accounts have their posts removed from your feed and from your notifications. Mutes are completely private." -msgstr "Les comptes masqués voient leurs posts supprimés de votre fil d’actualité et de vos notifications. Cette option est totalement privée." +msgstr "Les comptes masqués voient leurs posts supprimés de votre fil d’actu et de vos notifications. Cette option est totalement privée." #: src/view/screens/Moderation.tsx:100 msgid "Muted words & tags" -msgstr "" +msgstr "Les mots et les mots-clés masqués" #: src/view/screens/ProfileList.tsx:277 msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them." @@ -2419,7 +2281,7 @@ msgstr "Mes fils d’actu enregistrés" #: src/view/com/auth/server-input/index.tsx:118 msgid "my-server.com" -msgstr "" +msgstr "mon-serveur.fr" #: src/view/com/modals/AddAppPasswords.tsx:179 #: src/view/com/modals/CreateOrEditList.tsx:290 @@ -2432,7 +2294,7 @@ msgstr "Le nom est requis" #: src/screens/Onboarding/index.tsx:25 msgid "Nature" -msgstr "" +msgstr "Nature" #: src/view/com/auth/login/ForgotPasswordForm.tsx:190 #: src/view/com/auth/login/ForgotPasswordForm.tsx:219 @@ -2458,11 +2320,11 @@ msgstr "Ne perdez jamais l’accès à vos followers et à vos données." #: src/screens/Onboarding/StepFinished.tsx:119 msgid "Never lose access to your followers or data." -msgstr "" +msgstr "Ne perdez jamais l’accès à vos followers ou à vos données." -#: src/components/dialogs/MutedWords.tsx:244 +#: src/components/dialogs/MutedWords.tsx:293 msgid "Nevermind" -msgstr "" +msgstr "Peu importe" #: src/view/screens/Lists.tsx:76 msgctxt "action" @@ -2483,7 +2345,7 @@ msgstr "Nouveau mot de passe" #: src/view/com/modals/ChangePassword.tsx:215 msgid "New Password" -msgstr "" +msgstr "Nouveau mot de passe" #: src/view/com/feeds/FeedPage.tsx:126 msgctxt "action" @@ -2515,7 +2377,7 @@ msgstr "Réponses les plus récentes en premier" #: src/screens/Onboarding/index.tsx:23 msgid "News" -msgstr "" +msgstr "Actualités" #: src/view/com/auth/create/CreateAccount.tsx:172 #: src/view/com/auth/login/ForgotPasswordForm.tsx:182 @@ -2548,7 +2410,7 @@ msgid "No" msgstr "Non" #: src/view/screens/ProfileFeed.tsx:584 -#: src/view/screens/ProfileList.tsx:754 +#: src/view/screens/ProfileList.tsx:755 msgid "No description" msgstr "Aucune description" @@ -2558,16 +2420,20 @@ msgstr "Ne suit plus {0}" #: src/view/com/notifications/Feed.tsx:109 msgid "No notifications yet!" -msgstr "Pas encore de notifications !" +msgstr "Pas encore de notifications !" #: src/view/com/composer/text-input/mobile/Autocomplete.tsx:97 #: src/view/com/composer/text-input/web/Autocomplete.tsx:191 msgid "No result" msgstr "Aucun résultat" +#: src/components/Lists.tsx:192 +msgid "No results found" +msgstr "Aucun résultat trouvé" + #: src/view/screens/Feeds.tsx:495 msgid "No results found for \"{query}\"" -msgstr "Aucun résultat trouvé pour « {query} »" +msgstr "Aucun résultat trouvé pour « {query} »" #: src/view/com/modals/ListAddRemoveUsers.tsx:127 #: src/view/screens/Search/Search.tsx:281 @@ -2587,7 +2453,7 @@ msgstr "Personne" msgid "Not Applicable." msgstr "Sans objet." -#: src/Navigation.tsx:105 +#: src/Navigation.tsx:107 #: src/view/screens/Profile.tsx:106 msgid "Not Found" msgstr "Introuvable" @@ -2599,9 +2465,9 @@ msgstr "Pas maintenant" #: src/view/screens/Moderation.tsx:252 msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites." -msgstr "Remarque : Bluesky est un réseau ouvert et public. Ce paramètre limite uniquement la visibilité de votre contenu sur l’application et le site Web de Bluesky, et d’autres applications peuvent ne pas respecter ce paramètre. Votre contenu peut toujours être montré aux personnes non connectées par d’autres applications et sites Web." +msgstr "Remarque : Bluesky est un réseau ouvert et public. Ce paramètre limite uniquement la visibilité de votre contenu sur l’application et le site Web de Bluesky, et d’autres applications peuvent ne pas respecter ce paramètre. Votre contenu peut toujours être montré aux personnes non connectées par d’autres applications et sites Web." -#: src/Navigation.tsx:450 +#: src/Navigation.tsx:457 #: src/view/screens/Notifications.tsx:124 #: src/view/screens/Notifications.tsx:148 #: src/view/shell/bottom-bar/BottomBar.tsx:205 @@ -2617,11 +2483,11 @@ msgstr "Nudité" #: src/view/com/util/ErrorBoundary.tsx:35 msgid "Oh no!" -msgstr "Oh non !" +msgstr "Oh non !" #: src/screens/Onboarding/StepInterests/index.tsx:128 msgid "Oh no! Something went wrong." -msgstr "" +msgstr "Oh non ! Il y a eu un problème." #: src/view/com/auth/login/PasswordUpdatedForm.tsx:41 msgid "Okay" @@ -2643,18 +2509,23 @@ msgstr "Une ou plusieurs images n’ont pas de texte alt." msgid "Only {0} can reply." msgstr "Seul {0} peut répondre." +#: src/components/Lists.tsx:82 +msgid "Oops, something went wrong!" +msgstr "Oups, quelque chose n’a pas marché !" + +#: src/components/Lists.tsx:188 #: src/view/screens/AppPasswords.tsx:65 #: src/view/screens/Profile.tsx:106 msgid "Oops!" -msgstr "Oups !" +msgstr "Oups !" #: src/screens/Onboarding/StepFinished.tsx:115 msgid "Open" -msgstr "" +msgstr "Ouvrir" #: src/view/screens/Moderation.tsx:75 msgid "Open content filtering settings" -msgstr "" +msgstr "Ouvrir les paramètres de filtrage de contenu" #: src/view/com/composer/Composer.tsx:477 #: src/view/com/composer/Composer.tsx:478 @@ -2663,16 +2534,20 @@ msgstr "Ouvrir le sélecteur d’emoji" #: src/view/screens/Settings/index.tsx:712 msgid "Open links with in-app browser" -msgstr "" +msgstr "Ouvrir des liens avec le navigateur interne à l’appli" #: src/view/screens/Moderation.tsx:92 msgid "Open muted words settings" -msgstr "" +msgstr "Ouvrir les paramètres des mots masqués" -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:49 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:50 msgid "Open navigation" msgstr "Navigation ouverte" +#: src/view/com/util/forms/PostDropdownBtn.tsx:175 +msgid "Open post options menu" +msgstr "Ouvrir le menu d’options du post" + #: src/view/screens/Settings/index.tsx:804 msgid "Open storybook page" msgstr "Ouvrir la page Storybook" @@ -2685,7 +2560,7 @@ msgstr "Ouvre {numItems} options" msgid "Opens additional details for a debug entry" msgstr "Ouvre des détails supplémentaires pour une entrée de débug" -#: src/view/com/notifications/FeedItem.tsx:348 +#: src/view/com/notifications/FeedItem.tsx:349 msgid "Opens an expanded list of users in this notification" msgstr "Ouvre une liste étendue des comptes dans cette notification" @@ -2721,10 +2596,6 @@ msgstr "Ouvre la liste des comptes abonnés" msgid "Opens following list" msgstr "Ouvre la liste des abonnements" -#: src/view/screens/Settings.tsx:412 -#~ msgid "Opens invite code list" -#~ msgstr "Ouvre la liste des codes d’invitation" - #: src/view/com/modals/InviteCodes.tsx:172 msgid "Opens list of invite codes" msgstr "Ouvre la liste des codes d’invitation" @@ -2745,7 +2616,7 @@ msgstr "Ouvre les paramètres de modération" msgid "Opens password reset form" msgstr "Ouvre le formulaire de réinitialisation du mot de passe" -#: src/view/com/home/HomeHeaderLayout.web.tsx:60 +#: src/view/com/home/HomeHeaderLayout.web.tsx:63 #: src/view/screens/Feeds.tsx:356 msgid "Opens screen to edit Saved Feeds" msgstr "Ouvre l’écran pour modifier les fils d’actu enregistrés" @@ -2780,30 +2651,27 @@ msgstr "Option {0} sur {numItems}" #: src/view/com/modals/Threadgate.tsx:89 msgid "Or combine these options:" -msgstr "Ou une combinaison de ces options :" +msgstr "Ou une combinaison de ces options :" #: src/view/com/auth/login/ChooseAccountForm.tsx:138 msgid "Other account" msgstr "Autre compte" -#: src/view/com/modals/ServerInput.tsx:88 -#~ msgid "Other service" -#~ msgstr "Autre service" - #: src/view/com/composer/select-language/SelectLangBtn.tsx:91 msgid "Other..." msgstr "Autre…" +#: src/components/Lists.tsx:194 #: src/view/screens/NotFound.tsx:45 msgid "Page not found" msgstr "Page introuvable" #: src/view/screens/NotFound.tsx:42 msgid "Page Not Found" -msgstr "" +msgstr "Page introuvable" -#: src/view/com/auth/create/Step1.tsx:214 -#: src/view/com/auth/create/Step1.tsx:224 +#: src/view/com/auth/create/Step1.tsx:191 +#: src/view/com/auth/create/Step1.tsx:201 #: src/view/com/auth/login/LoginForm.tsx:226 #: src/view/com/auth/login/SetNewPasswordForm.tsx:161 #: src/view/com/modals/DeleteAccount.tsx:202 @@ -2816,13 +2684,13 @@ msgstr "Mise à jour du mot de passe" #: src/view/com/auth/login/PasswordUpdatedForm.tsx:28 msgid "Password updated!" -msgstr "Mot de passe mis à jour !" +msgstr "Mot de passe mis à jour !" -#: src/Navigation.tsx:160 +#: src/Navigation.tsx:162 msgid "People followed by @{0}" msgstr "Personnes suivies par @{0}" -#: src/Navigation.tsx:153 +#: src/Navigation.tsx:155 msgid "People following @{0}" msgstr "Personnes qui suivent @{0}" @@ -2836,11 +2704,7 @@ msgstr "Permission d’accès à la pellicule refusée. Veuillez l’activer dan #: src/screens/Onboarding/index.tsx:31 msgid "Pets" -msgstr "" - -#: src/view/com/auth/create/Step2.tsx:183 -#~ msgid "Phone number" -#~ msgstr "" +msgstr "Animaux domestiques" #: src/view/com/modals/SelfLabel.tsx:121 msgid "Pictures meant for adults." @@ -2878,7 +2742,7 @@ msgstr "Veuillez choisir votre mot de passe." #: src/view/com/auth/create/state.ts:131 msgid "Please complete the verification captcha." -msgstr "" +msgstr "Veuillez compléter le captcha de vérification." #: src/view/com/modals/ChangeEmail.tsx:67 msgid "Please confirm your email before changing it. This is a temporary requirement while email-updating tools are added, and it will soon be removed." @@ -2888,21 +2752,13 @@ msgstr "Veuillez confirmer votre e-mail avant de le modifier. Ceci est temporair msgid "Please enter a name for your app password. All spaces is not allowed." msgstr "Veuillez entrer un nom pour votre mot de passe d’application. Les espaces ne sont pas autorisés." -#: src/view/com/auth/create/Step2.tsx:206 -#~ msgid "Please enter a phone number that can receive SMS text messages." -#~ msgstr "" - #: src/view/com/modals/AddAppPasswords.tsx:145 msgid "Please enter a unique name for this App Password or use our randomly generated one." msgstr "Veuillez saisir un nom unique pour le mot de passe de l’application ou utiliser celui que nous avons généré de manière aléatoire." -#: src/view/com/auth/create/state.ts:170 -#~ msgid "Please enter the code you received by SMS." -#~ msgstr "" - -#: src/view/com/auth/create/Step2.tsx:282 -#~ msgid "Please enter the verification code sent to {phoneNumberFormatted}." -#~ msgstr "" +#: src/components/dialogs/MutedWords.tsx:68 +msgid "Please enter a valid word, tag, or phrase to mute" +msgstr "Veuillez entrer un mot, un mot-clé ou une phrase valide à masquer" #: src/view/com/auth/create/state.ts:103 msgid "Please enter your email." @@ -2910,12 +2766,12 @@ msgstr "Veuillez entrer votre e-mail." #: src/view/com/modals/DeleteAccount.tsx:191 msgid "Please enter your password as well:" -msgstr "Veuillez également entrer votre mot de passe :" +msgstr "Veuillez également entrer votre mot de passe :" #: src/view/com/modals/AppealLabel.tsx:72 #: src/view/com/modals/AppealLabel.tsx:75 msgid "Please tell us why you think this content warning was incorrectly applied!" -msgstr "Dites-nous donc pourquoi vous pensez que cet avertissement de contenu a été appliqué à tort !" +msgstr "Dites-nous donc pourquoi vous pensez que cet avertissement de contenu a été appliqué à tort !" #: src/view/com/modals/VerifyEmail.tsx:101 msgid "Please Verify Your Email" @@ -2927,7 +2783,7 @@ msgstr "Veuillez patienter le temps que votre carte de lien soit chargée" #: src/screens/Onboarding/index.tsx:37 msgid "Politics" -msgstr "" +msgstr "Politique" #: src/view/com/modals/SelfLabel.tsx:111 msgid "Porn" @@ -2948,13 +2804,13 @@ msgstr "Post" msgid "Post by {0}" msgstr "Post de {0}" -#: src/Navigation.tsx:172 -#: src/Navigation.tsx:179 -#: src/Navigation.tsx:186 +#: src/Navigation.tsx:174 +#: src/Navigation.tsx:181 +#: src/Navigation.tsx:188 msgid "Post by @{0}" msgstr "Post de @{0}" -#: src/view/com/util/forms/PostDropdownBtn.tsx:90 +#: src/view/com/util/forms/PostDropdownBtn.tsx:108 msgid "Post deleted" msgstr "Post supprimé" @@ -2974,17 +2830,17 @@ msgstr "Langues du post" msgid "Post not found" msgstr "Post introuvable" -#: src/components/TagMenu/index.tsx:257 +#: src/components/TagMenu/index.tsx:253 msgid "posts" -msgstr "" +msgstr "posts" #: src/view/screens/Profile.tsx:180 msgid "Posts" msgstr "Posts" -#: src/components/dialogs/MutedWords.tsx:77 +#: src/components/dialogs/MutedWords.tsx:90 msgid "Posts can be muted based on their text, their tags, or both." -msgstr "" +msgstr "Les posts peuvent être masqués en fonction de leur texte, de leurs mots-clés ou des deux." #: src/view/com/posts/FeedErrorMessage.tsx:64 msgid "Posts hidden" @@ -3011,7 +2867,7 @@ msgstr "Définissez des priorités de vos suivis" msgid "Privacy" msgstr "Vie privée" -#: src/Navigation.tsx:217 +#: src/Navigation.tsx:219 #: src/view/screens/PrivacyPolicy.tsx:29 #: src/view/screens/Settings/index.tsx:891 #: src/view/shell/Drawer.tsx:262 @@ -3040,7 +2896,7 @@ msgstr "Protégez votre compte en vérifiant votre e-mail." #: src/screens/Onboarding/StepFinished.tsx:101 msgid "Public" -msgstr "" +msgstr "Public" #: src/view/screens/ModerationModlists.tsx:61 msgid "Public, shareable lists of users to mute or block in bulk." @@ -3088,7 +2944,7 @@ msgstr "Fils d’actu recommandés" msgid "Recommended Users" msgstr "Comptes recommandés" -#: src/components/dialogs/MutedWords.tsx:249 +#: src/components/dialogs/MutedWords.tsx:298 #: src/view/com/modals/ListAddRemoveUsers.tsx:264 #: src/view/com/modals/SelfLabel.tsx:83 #: src/view/com/modals/UserAddRemoveLists.tsx:219 @@ -3099,7 +2955,7 @@ msgstr "Supprimer" #: src/view/com/feeds/FeedSourceCard.tsx:108 msgid "Remove {0} from my feeds?" -msgstr "Supprimer {0} de mes fils d’actu ?" +msgstr "Supprimer {0} de mes fils d’actu ?" #: src/view/com/util/AccountDropdownBtn.tsx:22 msgid "Remove account" @@ -3126,9 +2982,9 @@ msgstr "Supprimer l’image" msgid "Remove image preview" msgstr "Supprimer l’aperçu d’image" -#: src/components/dialogs/MutedWords.tsx:294 +#: src/components/dialogs/MutedWords.tsx:343 msgid "Remove mute word from your list" -msgstr "" +msgstr "Supprimer le mot masqué de votre liste" #: src/view/com/modals/Repost.tsx:47 msgid "Remove repost" @@ -3136,11 +2992,11 @@ msgstr "Supprimer le repost" #: src/view/com/feeds/FeedSourceCard.tsx:175 msgid "Remove this feed from my feeds?" -msgstr "Supprimer ce fil d’actu ?" +msgstr "Supprimer ce fil d’actu ?" #: src/view/com/posts/FeedErrorMessage.tsx:132 msgid "Remove this feed from your saved feeds?" -msgstr "Supprimer ce fil d’actu de vos fils d’actu enregistrés ?" +msgstr "Supprimer ce fil d’actu de vos fils d’actu enregistrés ?" #: src/view/com/modals/ListAddRemoveUsers.tsx:199 #: src/view/com/modals/UserAddRemoveLists.tsx:152 @@ -3196,7 +3052,8 @@ msgid "Report List" msgstr "Signaler la liste" #: src/view/com/modals/report/SendReportButton.tsx:37 -#: src/view/com/util/forms/PostDropdownBtn.tsx:255 +#: src/view/com/util/forms/PostDropdownBtn.tsx:301 +#: src/view/com/util/forms/PostDropdownBtn.tsx:309 msgid "Report post" msgstr "Signaler le post" @@ -3242,20 +3099,16 @@ msgstr "Reposts de ce post" msgid "Request Change" msgstr "Demande de modification" -#: src/view/com/auth/create/Step2.tsx:219 -#~ msgid "Request code" -#~ msgstr "" - #: src/view/com/modals/ChangePassword.tsx:239 #: src/view/com/modals/ChangePassword.tsx:241 msgid "Request Code" -msgstr "" +msgstr "Demander un code" #: src/view/screens/Settings/index.tsx:456 msgid "Require alt text before posting" msgstr "Nécessiter un texte alt avant de publier" -#: src/view/com/auth/create/Step1.tsx:153 +#: src/view/com/auth/create/Step1.tsx:146 msgid "Required for this provider" msgstr "Obligatoire pour cet hébergeur" @@ -3266,7 +3119,7 @@ msgstr "Réinitialiser le code" #: src/view/com/modals/ChangePassword.tsx:190 msgid "Reset Code" -msgstr "" +msgstr "Code de réinitialisation" #: src/view/screens/Settings/index.tsx:824 msgid "Reset onboarding" @@ -3316,18 +3169,10 @@ msgstr "Réessaye la dernière action, qui a échoué" msgid "Retry" msgstr "Réessayer" -#: src/view/com/auth/create/Step2.tsx:247 -#~ msgid "Retry." -#~ msgstr "" - -#: src/view/screens/ProfileList.tsx:898 +#: src/view/screens/ProfileList.tsx:903 msgid "Return to previous page" msgstr "Retourne à la page précédente" -#: src/view/shell/desktop/RightNav.tsx:55 -#~ msgid "SANDBOX. Posts and accounts are not permanent." -#~ msgstr "SANDBOX. Les posts et les comptes ne sont pas permanents." - #: src/view/com/lightbox/Lightbox.tsx:132 #: src/view/com/modals/CreateOrEditList.tsx:345 msgctxt "action" @@ -3373,13 +3218,13 @@ msgstr "Enregistre le changement de pseudo en {handle}" #: src/screens/Onboarding/index.tsx:36 msgid "Science" -msgstr "" +msgstr "Science" -#: src/view/screens/ProfileList.tsx:854 +#: src/view/screens/ProfileList.tsx:859 msgid "Scroll to top" msgstr "Remonter en haut" -#: src/Navigation.tsx:440 +#: src/Navigation.tsx:447 #: src/view/com/auth/LoggedOut.tsx:122 #: src/view/com/modals/ListAddRemoveUsers.tsx:75 #: src/view/com/util/forms/SearchInput.tsx:67 @@ -3399,15 +3244,15 @@ msgstr "Recherche" #: src/view/screens/Search/Search.tsx:735 #: src/view/shell/desktop/Search.tsx:255 msgid "Search for \"{query}\"" -msgstr "" +msgstr "Recherche de « {query} »" #: src/components/TagMenu/index.tsx:145 -msgid "Search for all posts by @{authorHandle} with tag {tag}" -msgstr "" +msgid "Search for all posts by @{authorHandle} with tag {displayTag}" +msgstr "Rechercher tous les posts de @{authorHandle} avec le mot-clé {displayTag}" -#: src/components/TagMenu/index.tsx:90 -msgid "Search for all posts with tag {tag}" -msgstr "" +#: src/components/TagMenu/index.tsx:94 +msgid "Search for all posts with tag {displayTag}" +msgstr "Rechercher tous les posts avec le mot-clé {displayTag}" #: src/view/com/auth/LoggedOut.tsx:104 #: src/view/com/auth/LoggedOut.tsx:105 @@ -3419,21 +3264,21 @@ msgstr "Rechercher des comptes" msgid "Security Step Required" msgstr "Étape de sécurité requise" -#: src/components/TagMenu/index.web.tsx:50 +#: src/components/TagMenu/index.web.tsx:66 msgid "See {truncatedTag} posts" -msgstr "" +msgstr "Voir les posts {truncatedTag}" -#: src/components/TagMenu/index.web.tsx:67 +#: src/components/TagMenu/index.web.tsx:83 msgid "See {truncatedTag} posts by user" -msgstr "" +msgstr "Voir les posts {truncatedTag} de ce compte" #: src/components/TagMenu/index.tsx:128 -msgid "See <0>{tag}</0> posts" -msgstr "" +msgid "See <0>{displayTag}</0> posts" +msgstr "Voir les posts <0>{displayTag}</0>" -#: src/components/TagMenu/index.tsx:189 -msgid "See <0>{tag}</0> posts by this user" -msgstr "" +#: src/components/TagMenu/index.tsx:187 +msgid "See <0>{displayTag}</0> posts by this user" +msgstr "Voir les posts <0>{displayTag}</0> de ce compte" #: src/view/screens/SavedFeeds.tsx:163 msgid "See this guide" @@ -3447,10 +3292,6 @@ msgstr "Voir la suite" msgid "Select {item}" msgstr "Sélectionner {item}" -#: src/view/com/modals/ServerInput.tsx:75 -#~ msgid "Select Bluesky Social" -#~ msgstr "Sélectionner Bluesky Social" - #: src/view/com/auth/login/Login.tsx:117 msgid "Select from an existing account" msgstr "Sélectionner un compte existant" @@ -3459,30 +3300,26 @@ msgstr "Sélectionner un compte existant" msgid "Select option {i} of {numItems}" msgstr "Sélectionne l’option {i} sur {numItems}" -#: src/view/com/auth/create/Step1.tsx:103 +#: src/view/com/auth/create/Step1.tsx:96 #: src/view/com/auth/login/LoginForm.tsx:150 msgid "Select service" msgstr "Sélectionner un service" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:52 msgid "Select some accounts below to follow" -msgstr "" +msgstr "Sélectionnez quelques comptes à suivre ci-dessous" #: src/view/com/auth/server-input/index.tsx:82 msgid "Select the service that hosts your data." -msgstr "" - -#: src/screens/Onboarding/StepModeration/index.tsx:49 -#~ msgid "Select the types of content that you want to see (or not see), and we'll handle the rest." -#~ msgstr "" +msgstr "Sélectionnez le service qui héberge vos données." #: src/screens/Onboarding/StepTopicalFeeds.tsx:96 msgid "Select topical feeds to follow from the list below" -msgstr "" +msgstr "Sélectionnez les fils d’actu thématiques à suivre dans la liste ci-dessous" #: src/screens/Onboarding/StepModeration/index.tsx:75 msgid "Select what you want to see (or not see), and we’ll handle the rest." -msgstr "" +msgstr "Sélectionnez ce que vous voulez voir (ou ne pas voir), et nous nous occupons du reste." #: src/view/screens/LanguageSettings.tsx:281 msgid "Select which languages you want your subscribed feeds to include. If none are selected, all languages will be shown." @@ -3494,11 +3331,7 @@ msgstr "Sélectionnez la langue de votre application à afficher par défaut" #: src/screens/Onboarding/StepInterests/index.tsx:196 msgid "Select your interests from the options below" -msgstr "" - -#: src/view/com/auth/create/Step2.tsx:155 -#~ msgid "Select your phone's country" -#~ msgstr "" +msgstr "Sélectionnez vos centres d’intérêt parmi les options ci-dessous" #: src/view/screens/LanguageSettings.tsx:190 msgid "Select your preferred language for translations in your feed." @@ -3506,11 +3339,11 @@ msgstr "Sélectionnez votre langue préférée pour traduire votre fils d’actu #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:116 msgid "Select your primary algorithmic feeds" -msgstr "" +msgstr "Sélectionnez vos principaux fils d’actu algorithmiques" #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:142 msgid "Select your secondary algorithmic feeds" -msgstr "" +msgstr "Sélectionnez vos fils d’actu algorithmiques secondaires" #: src/view/com/modals/VerifyEmail.tsx:202 #: src/view/com/modals/VerifyEmail.tsx:204 @@ -3541,7 +3374,7 @@ msgstr "Envoie un e-mail avec le code de confirmation pour la suppression du com #: src/view/com/auth/server-input/index.tsx:110 msgid "Server address" -msgstr "" +msgstr "Adresse du serveur" #: src/view/com/modals/ContentFilteringSettings.tsx:311 msgid "Set {value} for {labelGroup} content moderation policy" @@ -3567,47 +3400,43 @@ msgstr "Change le thème de couleur en fonction du paramètre système" #: src/view/screens/Settings/index.tsx:514 msgid "Set dark theme to the dark theme" -msgstr "" +msgstr "Choisir le thème le plus sombre comme thème sombre" #: src/view/screens/Settings/index.tsx:507 msgid "Set dark theme to the dim theme" -msgstr "" +msgstr "Choisir le thème atténué comme thème sombre" #: src/view/com/auth/login/SetNewPasswordForm.tsx:104 msgid "Set new password" msgstr "Définir un nouveau mot de passe" -#: src/view/com/auth/create/Step1.tsx:225 +#: src/view/com/auth/create/Step1.tsx:202 msgid "Set password" msgstr "Définit le mot de passe" #: src/view/screens/PreferencesFollowingFeed.tsx:225 msgid "Set this setting to \"No\" to hide all quote posts from your feed. Reposts will still be visible." -msgstr "Choisissez « Non » pour cacher toutes les citations sur votre fils d’actu. Les reposts seront toujours visibles." +msgstr "Choisissez « Non » pour cacher toutes les citations sur votre fils d’actu. Les reposts seront toujours visibles." #: src/view/screens/PreferencesFollowingFeed.tsx:122 msgid "Set this setting to \"No\" to hide all replies from your feed." -msgstr "Choisissez « Non » pour cacher toutes les réponses dans votre fils d’actu." +msgstr "Choisissez « Non » pour cacher toutes les réponses dans votre fils d’actu." #: src/view/screens/PreferencesFollowingFeed.tsx:191 msgid "Set this setting to \"No\" to hide all reposts from your feed." -msgstr "Choisissez « Non » pour cacher toutes les reposts de votre fils d’actu." +msgstr "Choisissez « Non » pour cacher toutes les reposts de votre fils d’actu." #: src/view/screens/PreferencesThreads.tsx:122 msgid "Set this setting to \"Yes\" to show replies in a threaded view. This is an experimental feature." -msgstr "Choisissez « Oui » pour afficher les réponses dans un fil de discussion. C’est une fonctionnalité expérimentale." - -#: src/view/screens/PreferencesHomeFeed.tsx:261 -#~ msgid "Set this setting to \"Yes\" to show samples of your saved feeds in your following feed. This is an experimental feature." -#~ msgstr "Choisissez « Oui » pour afficher des échantillons de vos fils d’actu enregistrés dans votre fils d’actu suivant. C’est une fonctionnalité expérimentale." +msgstr "Choisissez « Oui » pour afficher les réponses dans un fil de discussion. C’est une fonctionnalité expérimentale." #: src/view/screens/PreferencesFollowingFeed.tsx:261 msgid "Set this setting to \"Yes\" to show samples of your saved feeds in your Following feed. This is an experimental feature." -msgstr "" +msgstr "Choisissez « Oui » pour afficher des échantillons de vos fils d’actu enregistrés dans votre fil d’actu « Following ». C’est une fonctionnalité expérimentale." #: src/screens/Onboarding/Layout.tsx:50 msgid "Set up your account" -msgstr "" +msgstr "Créez votre compte" #: src/view/com/modals/ChangeHandle.tsx:266 msgid "Sets Bluesky username" @@ -3621,12 +3450,12 @@ msgstr "Définit l’e-mail pour la réinitialisation du mot de passe" msgid "Sets hosting provider for password reset" msgstr "Définit l’hébergeur pour la réinitialisation du mot de passe" -#: src/view/com/auth/create/Step1.tsx:104 +#: src/view/com/auth/create/Step1.tsx:97 #: src/view/com/auth/login/LoginForm.tsx:151 msgid "Sets server for the Bluesky client" msgstr "Définit le serveur pour le client Bluesky" -#: src/Navigation.tsx:135 +#: src/Navigation.tsx:137 #: src/view/screens/Settings/index.tsx:294 #: src/view/shell/desktop/LeftNav.tsx:433 #: src/view/shell/Drawer.tsx:567 @@ -3644,7 +3473,9 @@ msgid "Share" msgstr "Partager" #: src/view/com/profile/ProfileHeader.tsx:295 -#: src/view/com/util/forms/PostDropdownBtn.tsx:184 +#: src/view/com/util/forms/PostDropdownBtn.tsx:231 +#: src/view/com/util/forms/PostDropdownBtn.tsx:237 +#: src/view/com/util/post-ctrls/PostCtrls.tsx:215 #: src/view/screens/ProfileList.tsx:418 msgid "Share" msgstr "Partager" @@ -3693,15 +3524,15 @@ msgstr "Afficher les citations" #: src/screens/Onboarding/StepFollowingFeed.tsx:118 msgid "Show quote-posts in Following feed" -msgstr "" +msgstr "Afficher les citations dans le fil d’actu « Following »" #: src/screens/Onboarding/StepFollowingFeed.tsx:134 msgid "Show quotes in Following" -msgstr "" +msgstr "Afficher les citations dans le fil d’actu « Following »" #: src/screens/Onboarding/StepFollowingFeed.tsx:94 msgid "Show re-posts in Following feed" -msgstr "" +msgstr "Afficher les reposts dans le fil d’actu « Following »" #: src/view/screens/PreferencesFollowingFeed.tsx:119 msgid "Show Replies" @@ -3713,11 +3544,11 @@ msgstr "Afficher les réponses des personnes que vous suivez avant toutes les au #: src/screens/Onboarding/StepFollowingFeed.tsx:86 msgid "Show replies in Following" -msgstr "" +msgstr "Afficher les réponses dans le fil d’actu « Following »" #: src/screens/Onboarding/StepFollowingFeed.tsx:70 msgid "Show replies in Following feed" -msgstr "" +msgstr "Afficher les réponses dans le fil d’actu « Following »" #: src/view/screens/PreferencesFollowingFeed.tsx:70 msgid "Show replies with at least {value} {0}" @@ -3729,14 +3560,14 @@ msgstr "Afficher les reposts" #: src/screens/Onboarding/StepFollowingFeed.tsx:110 msgid "Show reposts in Following" -msgstr "" +msgstr "Afficher les reposts dans le fil d’actu « Following »" #: src/view/com/util/moderation/ContentHider.tsx:67 #: src/view/com/util/moderation/PostHider.tsx:61 msgid "Show the content" msgstr "Afficher le contenu" -#: src/view/com/notifications/FeedItem.tsx:346 +#: src/view/com/notifications/FeedItem.tsx:347 msgid "Show users" msgstr "Afficher les comptes" @@ -3829,27 +3660,19 @@ msgstr "Ignorer" #: src/screens/Onboarding/StepInterests/index.tsx:232 msgid "Skip this flow" -msgstr "" - -#: src/view/com/auth/create/Step2.tsx:82 -#~ msgid "SMS verification" -#~ msgstr "" +msgstr "Passer cette étape" #: src/screens/Onboarding/index.tsx:40 msgid "Software Dev" -msgstr "" +msgstr "Développement de logiciels" -#: src/view/com/modals/ProfilePreview.tsx:62 -#~ msgid "Something went wrong and we're not sure what." -#~ msgstr "Quelque chose n’a pas marché, mais on ne sait pas trop quoi." +#: src/components/Lists.tsx:203 +msgid "Something went wrong!" +msgstr "Quelque chose n’a pas marché !" -#: src/view/com/modals/Waitlist.tsx:51 -msgid "Something went wrong. Check your email and try again." -msgstr "Quelque chose n’a pas marché. Vérifiez vos e-mails et réessayez." - -#: src/App.native.tsx:63 +#: src/App.native.tsx:66 msgid "Sorry! Your session expired. Please log in again." -msgstr "Désolé ! Votre session a expiré. Essayez de vous reconnecter." +msgstr "Désolé ! Votre session a expiré. Essayez de vous reconnecter." #: src/view/screens/PreferencesThreads.tsx:69 msgid "Sort Replies" @@ -3857,20 +3680,16 @@ msgstr "Trier les réponses" #: src/view/screens/PreferencesThreads.tsx:72 msgid "Sort replies to the same post by:" -msgstr "Trier les réponses au même post par :" +msgstr "Trier les réponses au même post par :" #: src/screens/Onboarding/index.tsx:30 msgid "Sports" -msgstr "" +msgstr "Sports" #: src/view/com/modals/crop-image/CropImage.web.tsx:122 msgid "Square" msgstr "Carré" -#: src/view/com/modals/ServerInput.tsx:62 -#~ msgid "Staging" -#~ msgstr "Serveur de test" - #: src/view/screens/Settings/index.tsx:871 msgid "Status page" msgstr "État du service" @@ -3883,7 +3702,7 @@ msgstr "Étape {0} sur {numSteps}" msgid "Storage cleared, you need to restart the app now." msgstr "Stockage effacé, vous devez redémarrer l’application maintenant." -#: src/Navigation.tsx:202 +#: src/Navigation.tsx:204 #: src/view/screens/Settings/index.tsx:807 msgid "Storybook" msgstr "Historique" @@ -3897,9 +3716,9 @@ msgid "Subscribe" msgstr "S’abonner" #: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:173 -#: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:307 +#: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:308 msgid "Subscribe to the {0} feed" -msgstr "" +msgstr "S’abonner au fil d’actu {0}" #: src/view/screens/ProfileList.tsx:604 msgid "Subscribe to this list" @@ -3917,16 +3736,12 @@ msgstr "Suggérés pour vous" msgid "Suggestive" msgstr "Suggestif" -#: src/Navigation.tsx:212 +#: src/Navigation.tsx:214 #: src/view/screens/Support.tsx:30 #: src/view/screens/Support.tsx:33 msgid "Support" msgstr "Soutien" -#: src/view/com/modals/ProfilePreview.tsx:110 -#~ msgid "Swipe up to see more" -#~ msgstr "Glisser vers le haut pour en voir plus" - #: src/view/com/modals/SwitchAccount.tsx:117 msgid "Switch Account" msgstr "Changer de compte" @@ -3949,13 +3764,13 @@ msgstr "Système" msgid "System log" msgstr "Journal système" -#: src/components/dialogs/MutedWords.tsx:288 +#: src/components/dialogs/MutedWords.tsx:337 msgid "tag" -msgstr "" +msgstr "mot-clé" -#: src/components/TagMenu/index.tsx:74 -msgid "Tag menu: {tag}" -msgstr "" +#: src/components/TagMenu/index.tsx:78 +msgid "Tag menu: {displayTag}" +msgstr "Menu de mot-clé : {displayTag}" #: src/view/com/modals/crop-image/CropImage.web.tsx:112 msgid "Tall" @@ -3967,22 +3782,22 @@ msgstr "Tapper pour voir en entier" #: src/screens/Onboarding/index.tsx:39 msgid "Tech" -msgstr "" +msgstr "Technologie" #: src/view/shell/desktop/RightNav.tsx:81 msgid "Terms" msgstr "Conditions générales" -#: src/Navigation.tsx:222 +#: src/Navigation.tsx:224 #: src/view/screens/Settings/index.tsx:885 #: src/view/screens/TermsOfService.tsx:29 #: src/view/shell/Drawer.tsx:256 msgid "Terms of Service" msgstr "Conditions d’utilisation" -#: src/components/dialogs/MutedWords.tsx:288 +#: src/components/dialogs/MutedWords.tsx:337 msgid "text" -msgstr "" +msgstr "texte" #: src/view/com/modals/AppealLabel.tsx:70 #: src/view/com/modals/report/InputIssueDetails.tsx:51 @@ -3991,7 +3806,7 @@ msgstr "Champ de saisie de texte" #: src/view/com/auth/create/CreateAccount.tsx:94 msgid "That handle is already taken." -msgstr "" +msgstr "Ce pseudo est déjà occupé." #: src/view/com/profile/ProfileHeader.tsx:263 msgid "The account will be able to interact with you after unblocking." @@ -4007,7 +3822,7 @@ msgstr "Notre politique de droits d’auteur a été déplacée vers <0/>" #: src/screens/Onboarding/Layout.tsx:60 msgid "The following steps will help customize your Bluesky experience." -msgstr "" +msgstr "Les étapes suivantes vous aideront à personnaliser votre expérience avec Bluesky." #: src/view/com/post-thread/PostThread.tsx:517 msgid "The post may have been deleted." @@ -4027,7 +3842,7 @@ msgstr "Nos conditions d’utilisation ont été déplacées vers" #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:150 msgid "There are many feeds to try:" -msgstr "" +msgstr "Il existe de nombreux fils d’actu à essayer :" #: src/view/screens/ProfileFeed.tsx:550 msgid "There was an an issue contacting the server, please check your internet connection and try again." @@ -4061,7 +3876,7 @@ msgstr "Il y a eu un problème de connexion à votre serveur" msgid "There was an issue fetching notifications. Tap here to try again." msgstr "Il y a eu un problème lors de la récupération des notifications. Appuyez ici pour réessayer." -#: src/view/com/posts/Feed.tsx:263 +#: src/view/com/posts/Feed.tsx:265 msgid "There was an issue fetching posts. Tap here to try again." msgstr "Il y a eu un problème lors de la récupération des posts. Appuyez ici pour réessayer." @@ -4092,7 +3907,7 @@ msgstr "Il y a eu un problème lors de la récupération de vos mots de passe dâ #: src/view/com/profile/ProfileHeader.tsx:250 #: src/view/com/profile/ProfileHeader.tsx:272 msgid "There was an issue! {0}" -msgstr "Il y a eu un problème ! {0}" +msgstr "Il y a eu un problème ! {0}" #: src/view/screens/ProfileList.tsx:288 #: src/view/screens/ProfileList.tsx:307 @@ -4103,23 +3918,19 @@ msgstr "Il y a eu un problème. Veuillez vérifier votre connexion Internet et r #: src/view/com/util/ErrorBoundary.tsx:36 msgid "There was an unexpected issue in the application. Please let us know if this happened to you!" -msgstr "Un problème inattendu s’est produit dans l’application. N’hésitez pas à nous faire savoir si cela vous est arrivé !" +msgstr "Un problème inattendu s’est produit dans l’application. N’hésitez pas à nous faire savoir si cela vous est arrivé !" #: src/screens/Deactivated.tsx:106 msgid "There's been a rush of new users to Bluesky! We'll activate your account as soon as we can." -msgstr "" - -#: src/view/com/auth/create/Step2.tsx:55 -#~ msgid "There's something wrong with this number. Please choose your country and enter your full phone number!" -#~ msgstr "" +msgstr "Il y a eu un afflux de nouveaux personnes sur Bluesky ! Nous activerons ton compte dès que possible." #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:138 msgid "These are popular accounts you might like:" -msgstr "" +msgstr "Voici des comptes populaires qui pourraient vous intéresser :" #: src/view/com/util/moderation/ScreenHider.tsx:88 msgid "This {screenDescription} has been flagged:" -msgstr "Ce {screenDescription} a été signalé :" +msgstr "Ce {screenDescription} a été signalé :" #: src/view/com/util/moderation/ScreenHider.tsx:83 msgid "This account has requested that users sign in to view their profile." @@ -4127,7 +3938,7 @@ msgstr "Ce compte a demandé aux personnes de se connecter pour voir son profil. #: src/view/com/modals/EmbedConsent.tsx:68 msgid "This content is hosted by {0}. Do you want to enable external media?" -msgstr "Ce contenu est hébergé par {0}. Voulez-vous activer les médias externes ?" +msgstr "Ce contenu est hébergé par {0}. Voulez-vous activer les médias externes ?" #: src/view/com/modals/ModerationDetails.tsx:67 msgid "This content is not available because one of the users involved has blocked the other." @@ -4139,7 +3950,7 @@ msgstr "Ce contenu n’est pas visible sans un compte Bluesky." #: src/view/screens/Settings/ExportCarDialog.tsx:75 msgid "This feature is in beta. You can read more about repository exports in <0>this blogpost.</0>" -msgstr "" +msgstr "Cette fonctionnalité est en version bêta. Vous pouvez en savoir plus sur les exportations de dépôts dans <0>ce blogpost.</0>" #: src/view/com/posts/FeedErrorMessage.tsx:114 msgid "This feed is currently receiving high traffic and is temporarily unavailable. Please try again later." @@ -4149,11 +3960,11 @@ msgstr "Ce fil d’actu reçoit actuellement un trafic important, il est tempora #: src/view/screens/ProfileFeed.tsx:476 #: src/view/screens/ProfileList.tsx:661 msgid "This feed is empty!" -msgstr "Ce fil d’actu est vide !" +msgstr "Ce fil d’actu est vide !" #: src/view/com/posts/CustomFeedEmptyState.tsx:37 msgid "This feed is empty! You may need to follow more users or tune your language settings." -msgstr "Ce fil d’actu est vide ! Vous devriez peut-être suivre plus de comptes ou ajuster vos paramètres de langue." +msgstr "Ce fil d’actu est vide ! Vous devriez peut-être suivre plus de comptes ou ajuster vos paramètres de langue." #: src/view/com/modals/BirthDateSettings.tsx:61 msgid "This information is not shared with other users." @@ -4165,11 +3976,11 @@ msgstr "Ceci est important au cas où vous auriez besoin de changer d’e-mail o #: src/view/com/modals/LinkWarning.tsx:58 msgid "This link is taking you to the following website:" -msgstr "Ce lien vous conduit au site Web suivant :" +msgstr "Ce lien vous conduit au site Web suivant :" -#: src/view/screens/ProfileList.tsx:834 +#: src/view/screens/ProfileList.tsx:839 msgid "This list is empty!" -msgstr "Cette liste est vide !" +msgstr "Cette liste est vide !" #: src/view/com/modals/AddAppPasswords.tsx:106 msgid "This name is already in use" @@ -4189,21 +4000,17 @@ msgstr "Ce compte est inclus dans la liste <0/> que vous avez bloquée." #: src/view/com/modals/ModerationDetails.tsx:74 msgid "This user is included in the <0/> list which you have muted." -msgstr "" - -#: src/view/com/modals/ModerationDetails.tsx:74 -#~ msgid "This user is included the <0/> list which you have muted." -#~ msgstr "Ce compte est inclus dans la liste <0/> que vous avez masquée." +msgstr "Ce compte est inclus dans la liste <0/> que vous avez masquée." #: src/view/com/modals/SelfLabel.tsx:137 msgid "This warning is only available for posts with media attached." -msgstr "Cet avertissement n’est disponible que pour les messages contenant des médias." +msgstr "Cet avertissement n’est disponible que pour les posts contenant des médias." -#: src/components/dialogs/MutedWords.tsx:236 +#: src/components/dialogs/MutedWords.tsx:285 msgid "This will delete {0} from your muted words. You can always add it back later." -msgstr "" +msgstr "Cela supprimera {0} de vos mots masqués. Vous pourrez toujours le réintégrer plus tard." -#: src/view/com/util/forms/PostDropdownBtn.tsx:237 +#: src/view/com/util/forms/PostDropdownBtn.tsx:282 msgid "This will hide this post from your feeds." msgstr "Cela va masquer ce post de vos fils d’actu." @@ -4216,13 +4023,13 @@ msgstr "Préférences des fils de discussion" msgid "Threaded Mode" msgstr "Mode arborescent" -#: src/Navigation.tsx:255 +#: src/Navigation.tsx:257 msgid "Threads Preferences" msgstr "Préférences de fils de discussion" -#: src/components/dialogs/MutedWords.tsx:95 +#: src/components/dialogs/MutedWords.tsx:113 msgid "Toggle between muted word options." -msgstr "" +msgstr "Basculer entre les options pour les mots masqués." #: src/view/com/util/forms/DropdownButton.tsx:246 msgid "Toggle dropdown" @@ -4234,7 +4041,8 @@ msgstr "Transformations" #: src/view/com/post-thread/PostThreadItem.tsx:685 #: src/view/com/post-thread/PostThreadItem.tsx:687 -#: src/view/com/util/forms/PostDropdownBtn.tsx:156 +#: src/view/com/util/forms/PostDropdownBtn.tsx:215 +#: src/view/com/util/forms/PostDropdownBtn.tsx:217 msgid "Translate" msgstr "Traduire" @@ -4295,28 +4103,28 @@ msgid "Unfortunately, you do not meet the requirements to create an account." msgstr "Malheureusement, vous ne remplissez pas les conditions requises pour créer un compte." #: src/view/com/util/post-ctrls/PostCtrls.tsx:182 -#: src/view/com/util/post-ctrls/PostCtrls.tsx:216 msgid "Unlike" msgstr "Déliker" -#: src/components/TagMenu/index.tsx:253 +#: src/components/TagMenu/index.tsx:249 #: src/view/screens/ProfileList.tsx:597 msgid "Unmute" msgstr "Réafficher" -#: src/components/TagMenu/index.web.tsx:90 +#: src/components/TagMenu/index.web.tsx:104 msgid "Unmute {truncatedTag}" -msgstr "" +msgstr "Réafficher {truncatedTag}" #: src/view/com/profile/ProfileHeader.tsx:326 msgid "Unmute Account" msgstr "Réafficher ce compte" -#: src/components/TagMenu/index.tsx:210 -msgid "Unmute all {tag} posts" -msgstr "" +#: src/components/TagMenu/index.tsx:208 +msgid "Unmute all {displayTag} posts" +msgstr "Réafficher tous les posts {displayTag}" -#: src/view/com/util/forms/PostDropdownBtn.tsx:202 +#: src/view/com/util/forms/PostDropdownBtn.tsx:251 +#: src/view/com/util/forms/PostDropdownBtn.tsx:256 msgid "Unmute thread" msgstr "Réafficher ce fil de discussion" @@ -4347,7 +4155,7 @@ msgstr "Mise à jour…" #: src/view/com/modals/ChangeHandle.tsx:455 msgid "Upload a text file to:" -msgstr "Envoyer un fichier texte vers :" +msgstr "Envoyer un fichier texte vers :" #: src/view/screens/AppPasswords.tsx:195 msgid "Use app passwords to login to other Bluesky clients without giving full access to your account or password." @@ -4360,24 +4168,20 @@ msgstr "Utiliser le fournisseur par défaut" #: src/view/com/modals/InAppBrowserConsent.tsx:56 #: src/view/com/modals/InAppBrowserConsent.tsx:58 msgid "Use in-app browser" -msgstr "" +msgstr "Utiliser le navigateur interne à l’appli" #: src/view/com/modals/InAppBrowserConsent.tsx:66 #: src/view/com/modals/InAppBrowserConsent.tsx:68 msgid "Use my default browser" -msgstr "" +msgstr "Utiliser mon navigateur par défaut" #: src/view/com/modals/AddAppPasswords.tsx:155 msgid "Use this to sign into the other app along with your handle." msgstr "Utilisez-le pour vous connecter à l’autre application avec votre identifiant." -#: src/view/com/modals/ServerInput.tsx:105 -#~ msgid "Use your domain as your Bluesky client service provider" -#~ msgstr "Utilise votre domaine comme votre fournisseur de client Bluesky" - #: src/view/com/modals/InviteCodes.tsx:200 msgid "Used by:" -msgstr "Utilisé par :" +msgstr "Utilisé par :" #: src/view/com/modals/ModerationDetails.tsx:54 msgid "User Blocked" @@ -4400,13 +4204,13 @@ msgstr "Pseudo" msgid "User list by {0}" msgstr "Liste de compte de {0}" -#: src/view/screens/ProfileList.tsx:762 +#: src/view/screens/ProfileList.tsx:763 msgid "User list by <0/>" msgstr "Liste de compte par <0/>" #: src/view/com/lists/ListCard.tsx:83 #: src/view/com/modals/UserAddRemoveLists.tsx:196 -#: src/view/screens/ProfileList.tsx:760 +#: src/view/screens/ProfileList.tsx:761 msgid "User list by you" msgstr "Liste de compte par vous" @@ -4427,7 +4231,7 @@ msgstr "Listes de comptes" msgid "Username or email address" msgstr "Pseudo ou e-mail" -#: src/view/screens/ProfileList.tsx:796 +#: src/view/screens/ProfileList.tsx:797 msgid "Users" msgstr "Comptes" @@ -4437,11 +4241,7 @@ msgstr "comptes suivis par <0/>" #: src/view/com/modals/Threadgate.tsx:106 msgid "Users in \"{0}\"" -msgstr "Comptes dans « {0} »" - -#: src/view/com/auth/create/Step2.tsx:243 -#~ msgid "Verification code" -#~ msgstr "" +msgstr "Comptes dans « {0} »" #: src/view/screens/Settings/index.tsx:910 msgid "Verify email" @@ -4466,7 +4266,7 @@ msgstr "Vérifiez votre e-mail" #: src/screens/Onboarding/index.tsx:42 msgid "Video Games" -msgstr "" +msgstr "Jeux vidéo" #: src/view/com/profile/ProfileHeader.tsx:662 msgid "View {0}'s avatar" @@ -4499,39 +4299,39 @@ msgstr "Avertir" #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:134 msgid "We also think you'll like \"For You\" by Skygaze:" -msgstr "" +msgstr "Nous pensons également que vous aimerez « For You » de Skygaze :" + +#: src/screens/Hashtag.tsx:132 +msgid "We couldn't find any results for that hashtag." +msgstr "Nous n’avons trouvé aucun résultat pour ce mot-clé." #: src/screens/Deactivated.tsx:133 msgid "We estimate {estimatedTime} until your account is ready." -msgstr "" +msgstr "Nous estimons que votre compte sera prêt dans {estimatedTime}." #: src/screens/Onboarding/StepFinished.tsx:93 msgid "We hope you have a wonderful time. Remember, Bluesky is:" -msgstr "" +msgstr "Nous espérons que vous passerez un excellent moment. N’oubliez pas que Bluesky est :" #: src/view/com/posts/DiscoverFallbackHeader.tsx:29 msgid "We ran out of posts from your follows. Here's the latest from <0/>." -msgstr "" - -#: src/screens/Onboarding/StepAlgoFeeds/index.tsx:118 -#~ msgid "We recommend \"For You\" by Skygaze:" -#~ msgstr "" +msgstr "Nous n’avons plus de posts provenant des comptes que vous suivez. Voici le dernier de <0/>." -#: src/components/dialogs/MutedWords.tsx:161 +#: src/components/dialogs/MutedWords.tsx:204 msgid "We recommend avoiding common words that appear in many posts, since it can result in no posts being shown." -msgstr "" +msgstr "Nous vous recommandons d’éviter les mots communs qui apparaissent dans de nombreux posts, car cela peut avoir pour conséquence qu’aucun post ne s’affiche." #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:124 msgid "We recommend our \"Discover\" feed:" -msgstr "" +msgstr "Nous vous recommandons notre fil d’actu « Discover » :" #: src/screens/Onboarding/StepInterests/index.tsx:133 msgid "We weren't able to connect. Please try again to continue setting up your account. If it continues to fail, you can skip this flow." -msgstr "" +msgstr "Nous n’avons pas pu nous connecter. Veuillez réessayer pour continuer à configurer votre compte. Si l’échec persiste, vous pouvez sauter cette étape." #: src/screens/Deactivated.tsx:137 msgid "We will let you know when your account is ready." -msgstr "" +msgstr "Nous vous informerons lorsque votre compte sera prêt." #: src/view/com/modals/AppealLabel.tsx:48 msgid "We'll look into your appeal promptly." @@ -4539,27 +4339,28 @@ msgstr "Nous examinerons votre appel rapidement." #: src/screens/Onboarding/StepInterests/index.tsx:138 msgid "We'll use this to help customize your experience." -msgstr "" +msgstr "Nous utiliserons ces informations pour personnaliser votre expérience." #: src/view/com/auth/create/CreateAccount.tsx:134 msgid "We're so excited to have you join us!" -msgstr "Nous sommes ravis de vous accueillir !" +msgstr "Nous sommes ravis de vous accueillir !" #: src/view/screens/ProfileList.tsx:86 msgid "We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @{handleOrDid}." msgstr "Nous sommes désolés, mais nous n’avons pas pu charger cette liste. Si cela persiste, veuillez contacter l’origine de la liste, @{handleOrDid}." -#: src/components/dialogs/MutedWords.tsx:182 +#: src/components/dialogs/MutedWords.tsx:230 msgid "We're sorry, but we weren't able to load your muted words at this time. Please try again." -msgstr "" +msgstr "Nous sommes désolés, mais nous n’avons pas pu charger vos mots masqués pour le moment. Veuillez réessayer." #: src/view/screens/Search/Search.tsx:254 msgid "We're sorry, but your search could not be completed. Please try again in a few minutes." msgstr "Nous sommes désolés, mais votre recherche a été annulée. Veuillez réessayer dans quelques minutes." +#: src/components/Lists.tsx:211 #: src/view/screens/NotFound.tsx:48 msgid "We're sorry! We can't find the page you were looking for." -msgstr "Nous sommes désolés ! La page que vous recherchez est introuvable." +msgstr "Nous sommes désolés ! La page que vous recherchez est introuvable." #: src/view/com/auth/onboarding/WelcomeMobile.tsx:46 msgid "Welcome to <0>Bluesky</0>" @@ -4567,29 +4368,29 @@ msgstr "Bienvenue sur <0>Bluesky</0>" #: src/screens/Onboarding/StepInterests/index.tsx:130 msgid "What are your interests?" -msgstr "" +msgstr "Quels sont vos centres d’intérêt ?" #: src/view/com/modals/report/Modal.tsx:169 msgid "What is the issue with this {collectionName}?" -msgstr "Quel est le problème avec cette {collectionName} ?" +msgstr "Quel est le problème avec cette {collectionName} ?" #: src/view/com/auth/SplashScreen.tsx:59 #: src/view/com/composer/Composer.tsx:286 msgid "What's up?" -msgstr "Quoi de neuf ?" +msgstr "Quoi de neuf ?" #: src/view/com/modals/lang-settings/PostLanguagesSettings.tsx:78 msgid "Which languages are used in this post?" -msgstr "Quelles sont les langues utilisées dans ce post ?" +msgstr "Quelles sont les langues utilisées dans ce post ?" #: src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx:77 msgid "Which languages would you like to see in your algorithmic feeds?" -msgstr "Quelles langues aimeriez-vous voir apparaître dans vos flux algorithmiques ?" +msgstr "Quelles langues aimeriez-vous voir apparaître dans vos fils d’actu algorithmiques ?" #: src/view/com/composer/threadgate/ThreadgateBtn.tsx:47 #: src/view/com/modals/Threadgate.tsx:66 msgid "Who can reply" -msgstr "Qui peut répondre ?" +msgstr "Qui peut répondre ?" #: src/view/com/modals/crop-image/CropImage.web.tsx:102 msgid "Wide" @@ -4606,11 +4407,7 @@ msgstr "Rédigez votre réponse" #: src/screens/Onboarding/index.tsx:28 msgid "Writers" -msgstr "" - -#: src/view/com/auth/create/Step2.tsx:263 -#~ msgid "XXXXXX" -#~ msgstr "" +msgstr "Écrivain·e·s" #: src/view/com/composer/select-language/SuggestedLanguage.tsx:77 #: src/view/screens/PreferencesFollowingFeed.tsx:129 @@ -4622,26 +4419,18 @@ msgstr "" msgid "Yes" msgstr "Oui" -#: src/screens/Onboarding/StepModeration/index.tsx:46 -#~ msgid "You are in control" -#~ msgstr "" - #: src/screens/Deactivated.tsx:130 msgid "You are in line." -msgstr "" +msgstr "Vous êtes dans la file d’attente." #: src/view/com/posts/FollowingEmptyState.tsx:67 #: src/view/com/posts/FollowingEndOfFeed.tsx:68 msgid "You can also discover new Custom Feeds to follow." msgstr "Vous pouvez aussi découvrir de nouveaux fils d’actu personnalisés à suivre." -#: src/screens/Onboarding/StepAlgoFeeds/index.tsx:123 -#~ msgid "You can also try our \"Discover\" algorithm:" -#~ msgstr "" - #: src/screens/Onboarding/StepFollowingFeed.tsx:142 msgid "You can change these settings later." -msgstr "" +msgstr "Vous pouvez modifier ces paramètres ultérieurement." #: src/view/com/auth/login/Login.tsx:158 #: src/view/com/auth/login/PasswordUpdatedForm.tsx:31 @@ -4650,7 +4439,7 @@ msgstr "Vous pouvez maintenant vous connecter avec votre nouveau mot de passe." #: src/view/com/modals/InviteCodes.tsx:66 msgid "You don't have any invite codes yet! We'll send you some when you've been on Bluesky for a little longer." -msgstr "Vous n’avez encore aucun code d’invitation ! Nous vous en enverrons lorsque vous serez sur Bluesky depuis un peu plus longtemps." +msgstr "Vous n’avez encore aucun code d’invitation ! Nous vous en enverrons lorsque vous serez sur Bluesky depuis un peu plus longtemps." #: src/view/screens/SavedFeeds.tsx:102 msgid "You don't have any pinned feeds." @@ -4658,7 +4447,7 @@ msgstr "Vous n’avez encore aucun fil épinglé." #: src/view/screens/Feeds.tsx:452 msgid "You don't have any saved feeds!" -msgstr "Vous n’avez encore aucun fil enregistré !" +msgstr "Vous n’avez encore aucun fil enregistré !" #: src/view/screens/SavedFeeds.tsx:135 msgid "You don't have any saved feeds." @@ -4677,7 +4466,7 @@ msgstr "Vous avez bloqué ce compte. Vous ne pouvez pas voir son contenu." #: src/view/com/modals/ChangePassword.tsx:87 #: src/view/com/modals/ChangePassword.tsx:121 msgid "You have entered an invalid code. It should look like XXXXX-XXXXX." -msgstr "" +msgstr "Vous avez introduit un code non valide. Il devrait ressembler à XXXXX-XXXXX." #: src/view/com/modals/ModerationDetails.tsx:87 msgid "You have muted this user." @@ -4694,7 +4483,7 @@ msgstr "Vous n’avez aucune liste." #: src/view/screens/ModerationBlockedAccounts.tsx:132 msgid "You have not blocked any accounts yet. To block an account, go to their profile and selected \"Block account\" from the menu on their account." -msgstr "Vous n’avez pas encore bloqué de comptes. Pour bloquer un compte, accédez à son profil et sélectionnez « Bloquer le compte » dans le menu de son compte." +msgstr "Vous n’avez pas encore bloqué de comptes. Pour bloquer un compte, accédez à son profil et sélectionnez « Bloquer le compte » dans le menu de son compte." #: src/view/screens/AppPasswords.tsx:87 msgid "You have not created any app passwords yet. You can create one by pressing the button below." @@ -4702,11 +4491,11 @@ msgstr "Vous n’avez encore créé aucun mot de passe pour l’appli. Vous pouv #: src/view/screens/ModerationMutedAccounts.tsx:131 msgid "You have not muted any accounts yet. To mute an account, go to their profile and selected \"Mute account\" from the menu on their account." -msgstr "Vous n’avez encore masqué aucun compte. Pour désactiver un compte, allez sur son profil et sélectionnez « Masquer le compte » dans le menu de son compte." +msgstr "Vous n’avez encore masqué aucun compte. Pour désactiver un compte, allez sur son profil et sélectionnez « Masquer le compte » dans le menu de son compte." -#: src/components/dialogs/MutedWords.tsx:202 +#: src/components/dialogs/MutedWords.tsx:250 msgid "You haven't muted any words or tags yet" -msgstr "" +msgstr "Vous n’avez pas encore masqué de mot ou de mot-clé" #: src/view/com/modals/ContentFilteringSettings.tsx:175 msgid "You must be 18 or older to enable adult content." @@ -4714,39 +4503,39 @@ msgstr "Vous devez avoir 18 ans ou plus pour activer le contenu pour adultes." #: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:103 msgid "You must be 18 years or older to enable adult content" -msgstr "" +msgstr "Vous devez avoir 18 ans ou plus pour activer le contenu pour adultes." -#: src/view/com/util/forms/PostDropdownBtn.tsx:129 +#: src/view/com/util/forms/PostDropdownBtn.tsx:147 msgid "You will no longer receive notifications for this thread" msgstr "Vous ne recevrez plus de notifications pour ce fil de discussion" -#: src/view/com/util/forms/PostDropdownBtn.tsx:132 +#: src/view/com/util/forms/PostDropdownBtn.tsx:150 msgid "You will now receive notifications for this thread" msgstr "Vous recevrez désormais des notifications pour ce fil de discussion" #: src/view/com/auth/login/SetNewPasswordForm.tsx:107 msgid "You will receive an email with a \"reset code.\" Enter that code here, then enter your new password." -msgstr "Vous recevrez un e-mail contenant un « code de réinitialisation » Saisissez ce code ici, puis votre nouveau mot de passe." +msgstr "Vous recevrez un e-mail contenant un « code de réinitialisation ». Saisissez ce code ici, puis votre nouveau mot de passe." #: src/screens/Onboarding/StepModeration/index.tsx:72 msgid "You're in control" -msgstr "" +msgstr "Vous avez le contrôle" #: src/screens/Deactivated.tsx:87 #: src/screens/Deactivated.tsx:88 #: src/screens/Deactivated.tsx:103 msgid "You're in line" -msgstr "" +msgstr "Vous êtes dans la file d’attente" #: src/screens/Onboarding/StepFinished.tsx:90 msgid "You're ready to go!" -msgstr "" +msgstr "Vous êtes prêt à partir !" #: src/view/com/posts/FollowingEndOfFeed.tsx:48 msgid "You've reached the end of your feed! Find some more accounts to follow." -msgstr "Vous avez atteint la fin de votre fil d’actu ! Trouvez d’autres comptes à suivre." +msgstr "Vous avez atteint la fin de votre fil d’actu ! Trouvez d’autres comptes à suivre." -#: src/view/com/auth/create/Step1.tsx:74 +#: src/view/com/auth/create/Step1.tsx:67 msgid "Your account" msgstr "Votre compte" @@ -4756,19 +4545,19 @@ msgstr "Votre compte a été supprimé" #: src/view/screens/Settings/ExportCarDialog.tsx:47 msgid "Your account repository, containing all public data records, can be downloaded as a \"CAR\" file. This file does not include media embeds, such as images, or your private data, which must be fetched separately." -msgstr "" +msgstr "Le dépôt de votre compte, qui contient toutes les données publiques, peut être téléchargé sous la forme d’un fichier « CAR ». Ce fichier n’inclut pas les éléments multimédias, tels que les images, ni vos données privées, qui doivent être récupérées séparément." -#: src/view/com/auth/create/Step1.tsx:238 +#: src/view/com/auth/create/Step1.tsx:215 msgid "Your birth date" msgstr "Votre date de naissance" #: src/view/com/modals/InAppBrowserConsent.tsx:47 msgid "Your choice will be saved, but can be changed later in settings." -msgstr "" +msgstr "Votre choix sera enregistré, mais vous pourrez le modifier ultérieurement dans les paramètres." #: src/screens/Onboarding/StepFollowingFeed.tsx:61 msgid "Your default feed is \"Following\"" -msgstr "" +msgstr "Votre fil d’actu par défaut est « Following »" #: src/view/com/auth/create/state.ts:110 #: src/view/com/auth/login/ForgotPasswordForm.tsx:70 @@ -4776,10 +4565,6 @@ msgstr "" msgid "Your email appears to be invalid." msgstr "Votre e-mail semble être invalide." -#: src/view/com/modals/Waitlist.tsx:109 -msgid "Your email has been saved! We'll be in touch soon." -msgstr "Votre e-mail a été enregistré ! Nous vous contacterons bientôt." - #: src/view/com/modals/ChangeEmail.tsx:125 msgid "Your email has been updated but not verified. As a next step, please verify your new email." msgstr "Votre e-mail a été mis à jour, mais n’a pas été vérifié. L’étape suivante consiste à vérifier votre nouvel e-mail." @@ -4790,7 +4575,7 @@ msgstr "Votre e-mail n’a pas encore été vérifié. Il s’agit d’une mesur #: src/view/com/posts/FollowingEmptyState.tsx:47 msgid "Your following feed is empty! Follow more users to see what's happening." -msgstr "Votre fil d’actu des comptes suivis est vide ! Suivez plus de comptes pour voir ce qui se passe." +msgstr "Votre fil d’actu des comptes suivis est vide ! Suivez plus de comptes pour voir ce qui se passe." #: src/view/com/auth/create/Step2.tsx:83 msgid "Your full handle will be" @@ -4800,19 +4585,13 @@ msgstr "Votre nom complet sera" msgid "Your full handle will be <0>@{0}</0>" msgstr "Votre pseudo complet sera <0>@{0}</0>" -#: src/view/screens/Settings.tsx:430 -#: src/view/shell/desktop/RightNav.tsx:137 -#: src/view/shell/Drawer.tsx:660 -#~ msgid "Your invite codes are hidden when logged in using an App Password" -#~ msgstr "Vos codes d’invitation sont cachés lorsque vous êtes connecté à l’aide d’un mot de passe d’application." - -#: src/components/dialogs/MutedWords.tsx:173 +#: src/components/dialogs/MutedWords.tsx:221 msgid "Your muted words" -msgstr "" +msgstr "Vos mots masqués" #: src/view/com/modals/ChangePassword.tsx:155 msgid "Your password has been changed successfully!" -msgstr "" +msgstr "Votre mot de passe a été modifié avec succès !" #: src/view/com/composer/Composer.tsx:274 msgid "Your post has been published" diff --git a/src/locale/locales/hi/messages.po b/src/locale/locales/hi/messages.po index 7d852d0b5..ae0215aac 100644 --- a/src/locale/locales/hi/messages.po +++ b/src/locale/locales/hi/messages.po @@ -79,12 +79,12 @@ msgstr "" msgid "A new version of the app is available. Please update to continue using the app." msgstr "à¤à¤ª का à¤à¤• नया संसà¥à¤•रण उपलबà¥à¤§ है. कृपया à¤à¤ª का उपयोग जारी रखने के लिठअपडेट करें।" -#: src/view/com/util/ViewHeader.tsx:83 +#: src/view/com/util/ViewHeader.tsx:89 #: src/view/screens/Search/Search.tsx:647 msgid "Access navigation links and settings" msgstr "" -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:51 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:52 msgid "Access profile and other navigation links" msgstr "" @@ -131,11 +131,11 @@ msgstr "" msgid "Account unmuted" msgstr "" -#: src/components/dialogs/MutedWords.tsx:147 +#: src/components/dialogs/MutedWords.tsx:165 #: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:150 #: src/view/com/modals/ListAddRemoveUsers.tsx:264 #: src/view/com/modals/UserAddRemoveLists.tsx:219 -#: src/view/screens/ProfileList.tsx:812 +#: src/view/screens/ProfileList.tsx:813 msgid "Add" msgstr "à¤à¤¡ करो" @@ -143,7 +143,7 @@ msgstr "à¤à¤¡ करो" msgid "Add a content warning" msgstr "सामगà¥à¤°à¥€ चेतावनी जोड़ें" -#: src/view/screens/ProfileList.tsx:802 +#: src/view/screens/ProfileList.tsx:803 msgid "Add a user to this list" msgstr "इस सूची में किसी को जोड़ें" @@ -181,11 +181,11 @@ msgstr "लिंक कारà¥à¤¡ जोड़ें" msgid "Add link card:" msgstr "लिंक कारà¥à¤¡ जोड़ें:" -#: src/components/dialogs/MutedWords.tsx:140 +#: src/components/dialogs/MutedWords.tsx:158 msgid "Add mute word for configured settings" msgstr "" -#: src/components/dialogs/MutedWords.tsx:74 +#: src/components/dialogs/MutedWords.tsx:87 msgid "Add muted words and tags" msgstr "" @@ -273,7 +273,7 @@ msgstr "{0} को ईमेल à¤à¥‡à¤œà¤¾ गया है। इसमें msgid "An issue occurred, please try again." msgstr "" -#: src/view/com/notifications/FeedItem.tsx:236 +#: src/view/com/notifications/FeedItem.tsx:237 #: src/view/com/threadgate/WhoCanReply.tsx:178 msgid "and" msgstr "और" @@ -306,13 +306,14 @@ msgstr "" #~ msgid "App passwords" #~ msgstr "à¤à¤ª पासवरà¥à¤¡" -#: src/Navigation.tsx:237 +#: src/Navigation.tsx:239 #: src/view/screens/AppPasswords.tsx:187 #: src/view/screens/Settings/index.tsx:684 msgid "App Passwords" msgstr "à¤à¤ª पासवरà¥à¤¡" -#: src/view/com/util/forms/PostDropdownBtn.tsx:295 +#: src/view/com/util/forms/PostDropdownBtn.tsx:337 +#: src/view/com/util/forms/PostDropdownBtn.tsx:346 msgid "Appeal content warning" msgstr "" @@ -340,12 +341,12 @@ msgstr "कà¥à¤¯à¤¾ आप वाकई à¤à¤ª पासवरà¥à¤¡ \"{name}\" msgid "Are you sure you'd like to discard this draft?" msgstr "कà¥à¤¯à¤¾ आप वाकई इस डà¥à¤°à¤¾à¤«à¥à¤Ÿ को हटाना करना चाहेंगे?" -#: src/components/dialogs/MutedWords.tsx:233 +#: src/components/dialogs/MutedWords.tsx:282 #: src/view/screens/ProfileList.tsx:365 msgid "Are you sure?" msgstr "कà¥à¤¯à¤¾ आप वासà¥à¤¤à¤µ में इसे करना चाहते हैं?" -#: src/view/com/util/forms/PostDropdownBtn.tsx:278 +#: src/view/com/util/forms/PostDropdownBtn.tsx:322 msgid "Are you sure? This cannot be undone." msgstr "कà¥à¤¯à¤¾ आप वासà¥à¤¤à¤µ में इसे करना चाहते हैं? इसे असंपादित नहीं किया जा सकता है।" @@ -371,7 +372,7 @@ msgstr "कलातà¥à¤®à¤• या गैर-कामà¥à¤• नगà¥à¤¨à¤¤à¤ #: src/view/com/post-thread/PostThread.tsx:522 #: src/view/com/post-thread/PostThread.tsx:530 #: src/view/com/profile/ProfileHeader.tsx:649 -#: src/view/com/util/ViewHeader.tsx:81 +#: src/view/com/util/ViewHeader.tsx:87 msgid "Back" msgstr "वापस" @@ -388,7 +389,7 @@ msgstr "" msgid "Basics" msgstr "मूल बातें" -#: src/view/com/auth/create/Step1.tsx:250 +#: src/view/com/auth/create/Step1.tsx:227 #: src/view/com/modals/BirthDateSettings.tsx:73 msgid "Birthday" msgstr "जनà¥à¤®à¤¦à¤¿à¤¨" @@ -427,7 +428,7 @@ msgstr "" msgid "Blocked accounts" msgstr "बà¥à¤²à¥‰à¤• किठगठखाते" -#: src/Navigation.tsx:130 +#: src/Navigation.tsx:132 #: src/view/screens/ModerationBlockedAccounts.tsx:107 msgid "Blocked Accounts" msgstr "बà¥à¤²à¥‰à¤• किठगठखाते" @@ -479,8 +480,8 @@ msgid "Bluesky is public." msgstr "Bluesky सारà¥à¤µà¤œà¤¨à¤¿à¤• है।।" #: src/view/com/modals/Waitlist.tsx:70 -msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon." -msgstr "बà¥à¤²à¥‚सà¥à¤•ी à¤à¤• सà¥à¤µà¤¸à¥à¤¥ समà¥à¤¦à¤¾à¤¯ बनाने के लिठआमंतà¥à¤°à¤¿à¤¤ करता है। यदि आप किसी को आमंतà¥à¤°à¤¿à¤¤ नहीं करते हैं, तो आप पà¥à¤°à¤¤à¥€à¤•à¥à¤·à¤¾ सूची के लिठसाइन अप कर सकते हैं और हम जलà¥à¤¦ ही à¤à¤• à¤à¥‡à¤œ देंगे।।" +#~ msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon." +#~ msgstr "बà¥à¤²à¥‚सà¥à¤•ी à¤à¤• सà¥à¤µà¤¸à¥à¤¥ समà¥à¤¦à¤¾à¤¯ बनाने के लिठआमंतà¥à¤°à¤¿à¤¤ करता है। यदि आप किसी को आमंतà¥à¤°à¤¿à¤¤ नहीं करते हैं, तो आप पà¥à¤°à¤¤à¥€à¤•à¥à¤·à¤¾ सूची के लिठसाइन अप कर सकते हैं और हम जलà¥à¤¦ ही à¤à¤• à¤à¥‡à¤œ देंगे।।" #: src/view/screens/Moderation.tsx:245 msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private." @@ -533,7 +534,7 @@ msgstr "कैमरा" msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must be at least 4 characters long, but no more than 32 characters long." msgstr "केवल अकà¥à¤·à¤°, संखà¥à¤¯à¤¾, रिकà¥à¤¤ सà¥à¤¥à¤¾à¤¨, डैश और अंडरसà¥à¤•ोर हो सकते हैं। कम से कम 4 अकà¥à¤·à¤° लंबा होना चाहिà¤, लेकिन 32 अकà¥à¤·à¤°à¥‹à¤‚ से अधिक लंबा नहीं होना चाहिà¤à¥¤à¥¤" -#: src/components/Prompt.tsx:91 +#: src/components/Prompt.tsx:101 #: src/view/com/composer/Composer.tsx:307 #: src/view/com/composer/Composer.tsx:312 #: src/view/com/modals/ChangeEmail.tsx:218 @@ -548,7 +549,6 @@ msgstr "केवल अकà¥à¤·à¤°, संखà¥à¤¯à¤¾, रिकà¥à¤¤ सॠ#: src/view/com/modals/Repost.tsx:87 #: src/view/com/modals/VerifyEmail.tsx:247 #: src/view/com/modals/VerifyEmail.tsx:253 -#: src/view/com/modals/Waitlist.tsx:142 #: src/view/screens/Search/Search.tsx:716 #: src/view/shell/desktop/Search.tsx:238 msgid "Cancel" @@ -590,8 +590,8 @@ msgid "Cancel search" msgstr "खोज मत करो" #: src/view/com/modals/Waitlist.tsx:136 -msgid "Cancel waitlist signup" -msgstr "पà¥à¤°à¤¤à¥€à¤•à¥à¤·à¤¾ सूची पंजीकरण मत करो" +#~ msgid "Cancel waitlist signup" +#~ msgstr "पà¥à¤°à¤¤à¥€à¤•à¥à¤·à¤¾ सूची पंजीकरण मत करो" #: src/view/screens/Settings/index.tsx:334 msgctxt "action" @@ -677,7 +677,7 @@ msgstr "उन à¤à¤²à¥à¤—ोरिदम का चयन करें जो msgid "Choose your main feeds" msgstr "" -#: src/view/com/auth/create/Step1.tsx:219 +#: src/view/com/auth/create/Step1.tsx:196 msgid "Choose your password" msgstr "अपना पासवरà¥à¤¡ चà¥à¤¨à¥‡à¤‚" @@ -708,11 +708,14 @@ msgstr "खोज कà¥à¤µà¥‡à¤°à¥€ साफ़ करें" msgid "click here" msgstr "" -#: src/components/RichText.tsx:189 -#: src/components/TagMenu/index.web.tsx:125 +#: src/components/TagMenu/index.web.tsx:138 msgid "Click here to open tag menu for {tag}" msgstr "" +#: src/components/RichText.tsx:191 +msgid "Click here to open tag menu for #{tag}" +msgstr "" + #: src/screens/Onboarding/index.tsx:35 msgid "Climate" msgstr "" @@ -722,8 +725,8 @@ msgstr "" msgid "Close" msgstr "" -#: src/components/Dialog/index.web.tsx:80 -#: src/components/Dialog/index.web.tsx:194 +#: src/components/Dialog/index.web.tsx:84 +#: src/components/Dialog/index.web.tsx:198 msgid "Close active dialog" msgstr "" @@ -747,7 +750,7 @@ msgstr "छवि बंद करें" msgid "Close navigation footer" msgstr "नेविगेशन पाद बंद करें" -#: src/components/TagMenu/index.tsx:266 +#: src/components/TagMenu/index.tsx:262 msgid "Close this dialog" msgstr "" @@ -767,7 +770,7 @@ msgstr "" msgid "Closes viewer for header image" msgstr "" -#: src/view/com/notifications/FeedItem.tsx:317 +#: src/view/com/notifications/FeedItem.tsx:318 msgid "Collapses list of users for a given notification" msgstr "" @@ -779,7 +782,7 @@ msgstr "" msgid "Comics" msgstr "" -#: src/Navigation.tsx:227 +#: src/Navigation.tsx:229 #: src/view/screens/CommunityGuidelines.tsx:32 msgid "Community Guidelines" msgstr "समà¥à¤¦à¤¾à¤¯ दिशानिरà¥à¤¦à¥‡à¤¶" @@ -804,7 +807,7 @@ msgstr "जवाब लिखो" msgid "Configure content filtering setting for category: {0}" msgstr "" -#: src/components/Prompt.tsx:113 +#: src/components/Prompt.tsx:124 #: src/view/com/modals/AppealLabel.tsx:98 #: src/view/com/modals/SelfLabel.tsx:154 #: src/view/com/modals/VerifyEmail.tsx:231 @@ -844,8 +847,8 @@ msgid "Confirmation code" msgstr "OTP कोड" #: src/view/com/modals/Waitlist.tsx:120 -msgid "Confirms signing up {email} to the waitlist" -msgstr "" +#~ msgid "Confirms signing up {email} to the waitlist" +#~ msgstr "" #: src/view/com/auth/create/CreateAccount.tsx:193 #: src/view/com/auth/login/LoginForm.tsx:278 @@ -922,7 +925,7 @@ msgstr "" #: src/view/com/modals/AddAppPasswords.tsx:76 #: src/view/com/modals/InviteCodes.tsx:152 -#: src/view/com/util/forms/PostDropdownBtn.tsx:143 +#: src/view/com/util/forms/PostDropdownBtn.tsx:161 msgid "Copied to clipboard" msgstr "" @@ -938,7 +941,8 @@ msgstr "कॉपी" msgid "Copy link to list" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:184 +#: src/view/com/util/forms/PostDropdownBtn.tsx:231 +#: src/view/com/util/forms/PostDropdownBtn.tsx:237 msgid "Copy link to post" msgstr "" @@ -946,11 +950,12 @@ msgstr "" msgid "Copy link to profile" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:170 +#: src/view/com/util/forms/PostDropdownBtn.tsx:223 +#: src/view/com/util/forms/PostDropdownBtn.tsx:225 msgid "Copy post text" msgstr "पोसà¥à¤Ÿ टेकà¥à¤¸à¥à¤Ÿ कॉपी करें" -#: src/Navigation.tsx:232 +#: src/Navigation.tsx:234 #: src/view/screens/CopyrightPolicy.tsx:29 msgid "Copyright Policy" msgstr "कॉपीराइट नीति" @@ -959,7 +964,7 @@ msgstr "कॉपीराइट नीति" msgid "Could not load feed" msgstr "फ़ीड लोड नहीं कर सकता" -#: src/view/screens/ProfileList.tsx:888 +#: src/view/screens/ProfileList.tsx:893 msgid "Could not load list" msgstr "सूची लोड नहीं कर सकता" @@ -1079,11 +1084,12 @@ msgstr "मेरा खाता हटाà¤à¤‚" msgid "Delete My Account…" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:273 +#: src/view/com/util/forms/PostDropdownBtn.tsx:317 +#: src/view/com/util/forms/PostDropdownBtn.tsx:326 msgid "Delete post" msgstr "पोसà¥à¤Ÿ को हटाà¤à¤‚" -#: src/view/com/util/forms/PostDropdownBtn.tsx:277 +#: src/view/com/util/forms/PostDropdownBtn.tsx:321 msgid "Delete this post?" msgstr "इस पोसà¥à¤Ÿ को डीलीट करें?" @@ -1152,8 +1158,8 @@ msgid "Domain verified!" msgstr "डोमेन सतà¥à¤¯à¤¾à¤ªà¤¿à¤¤!" #: src/view/com/auth/create/Step1.tsx:170 -msgid "Don't have an invite code?" -msgstr "" +#~ msgid "Don't have an invite code?" +#~ msgstr "" #: src/view/com/auth/onboarding/RecommendedFollows.tsx:86 #: src/view/com/modals/EditImage.tsx:333 @@ -1255,7 +1261,7 @@ msgstr "सूची विवरण संपादित करें" msgid "Edit Moderation List" msgstr "" -#: src/Navigation.tsx:242 +#: src/Navigation.tsx:244 #: src/view/screens/Feeds.tsx:434 #: src/view/screens/SavedFeeds.tsx:84 msgid "Edit My Feeds" @@ -1273,7 +1279,7 @@ msgstr "मेरी पà¥à¤°à¥‹à¤«à¤¼à¤¾à¤‡à¤² संपादित करे msgid "Edit Profile" msgstr "मेरी पà¥à¤°à¥‹à¤«à¤¼à¤¾à¤‡à¤² संपादित करें" -#: src/view/com/home/HomeHeaderLayout.web.tsx:59 +#: src/view/com/home/HomeHeaderLayout.web.tsx:62 #: src/view/screens/Feeds.tsx:355 msgid "Edit Saved Feeds" msgstr "à¤à¤¡à¤¿à¤Ÿ सेवà¥à¤¡ फीड" @@ -1294,14 +1300,13 @@ msgstr "" msgid "Education" msgstr "" -#: src/view/com/auth/create/Step1.tsx:199 +#: src/view/com/auth/create/Step1.tsx:176 #: src/view/com/auth/login/ForgotPasswordForm.tsx:156 #: src/view/com/modals/ChangeEmail.tsx:141 -#: src/view/com/modals/Waitlist.tsx:88 msgid "Email" msgstr "ईमेल" -#: src/view/com/auth/create/Step1.tsx:190 +#: src/view/com/auth/create/Step1.tsx:167 #: src/view/com/auth/login/ForgotPasswordForm.tsx:147 msgid "Email address" msgstr "ईमेल" @@ -1356,8 +1361,8 @@ msgstr "" msgid "Enter a name for this App Password" msgstr "" -#: src/components/dialogs/MutedWords.tsx:87 -#: src/components/dialogs/MutedWords.tsx:88 +#: src/components/dialogs/MutedWords.tsx:100 +#: src/components/dialogs/MutedWords.tsx:101 msgid "Enter a word or tag" msgstr "" @@ -1377,16 +1382,16 @@ msgstr "आप जिस डोमेन का उपयोग करना च msgid "Enter the email you used to create your account. We'll send you a \"reset code\" so you can set a new password." msgstr "वह ईमेल दरà¥à¤œ करें जिसका उपयोग आपने अपना खाता बनाने के लिठकिया था। हम आपको à¤à¤• \"reset code\" à¤à¥‡à¤œà¥‡à¤‚गे ताकि आप à¤à¤• नया पासवरà¥à¤¡ सेट कर सकें।" -#: src/view/com/auth/create/Step1.tsx:251 +#: src/view/com/auth/create/Step1.tsx:228 #: src/view/com/modals/BirthDateSettings.tsx:74 msgid "Enter your birth date" msgstr "" #: src/view/com/modals/Waitlist.tsx:78 -msgid "Enter your email" -msgstr "" +#~ msgid "Enter your email" +#~ msgstr "" -#: src/view/com/auth/create/Step1.tsx:195 +#: src/view/com/auth/create/Step1.tsx:172 msgid "Enter your email address" msgstr "अपना ईमेल पता दरà¥à¤œ करें" @@ -1432,8 +1437,8 @@ msgid "Exits inputting search query" msgstr "" #: src/view/com/modals/Waitlist.tsx:138 -msgid "Exits signing up for waitlist with {email}" -msgstr "" +#~ msgid "Exits signing up for waitlist with {email}" +#~ msgstr "" #: src/view/com/lightbox/Lightbox.web.tsx:163 msgid "Expand alt text" @@ -1462,7 +1467,7 @@ msgstr "" msgid "External media may allow websites to collect information about you and your device. No information is sent or requested until you press the \"play\" button." msgstr "" -#: src/Navigation.tsx:261 +#: src/Navigation.tsx:263 #: src/view/screens/PreferencesExternalEmbeds.tsx:52 #: src/view/screens/Settings/index.tsx:657 msgid "External Media Preferences" @@ -1481,7 +1486,7 @@ msgstr "" msgid "Failed to create the list. Check your internet connection and try again." msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:110 +#: src/view/com/util/forms/PostDropdownBtn.tsx:128 msgid "Failed to delete post, please try again" msgstr "" @@ -1490,7 +1495,7 @@ msgstr "" msgid "Failed to load recommended feeds" msgstr "अनà¥à¤¶à¤‚सित फ़ीड लोड करने में विफल" -#: src/Navigation.tsx:192 +#: src/Navigation.tsx:194 msgid "Feed" msgstr "" @@ -1511,7 +1516,7 @@ msgstr "फ़ीड ऑफ़लाइन है" msgid "Feedback" msgstr "पà¥à¤°à¤¤à¤¿à¤•à¥à¤°à¤¿à¤¯à¤¾" -#: src/Navigation.tsx:445 +#: src/Navigation.tsx:452 #: src/view/screens/Feeds.tsx:419 #: src/view/screens/Feeds.tsx:524 #: src/view/screens/Profile.tsx:184 @@ -1652,9 +1657,9 @@ msgstr "फोलà¥à¤²à¥‹à¤µà¤¿à¤‚ग" msgid "Following {0}" msgstr "" -#: src/Navigation.tsx:248 -#: src/view/com/home/HomeHeaderLayout.web.tsx:45 -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:83 +#: src/Navigation.tsx:250 +#: src/view/com/home/HomeHeaderLayout.web.tsx:50 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:84 #: src/view/screens/PreferencesFollowingFeed.tsx:104 #: src/view/screens/Settings/index.tsx:543 msgid "Following Feed Preferences" @@ -1693,6 +1698,11 @@ msgstr "पासवरà¥à¤¡ à¤à¥‚ल गà¤" msgid "Forgot Password" msgstr "पासवरà¥à¤¡ à¤à¥‚ल गà¤" +#: src/screens/Hashtag.tsx:108 +#: src/screens/Hashtag.tsx:148 +msgid "From @{sanitizedAuthor}" +msgstr "" + #: src/view/com/posts/FeedItem.tsx:189 msgctxt "from-feed" msgid "From <0/>" @@ -1716,8 +1726,8 @@ msgstr "वापस जाओ" #: src/view/screens/ProfileFeed.tsx:106 #: src/view/screens/ProfileFeed.tsx:111 -#: src/view/screens/ProfileList.tsx:897 #: src/view/screens/ProfileList.tsx:902 +#: src/view/screens/ProfileList.tsx:907 msgid "Go Back" msgstr "वापस जाओ" @@ -1743,8 +1753,16 @@ msgstr "अगला" msgid "Handle" msgstr "हैंडल" +#: src/Navigation.tsx:270 +msgid "Hashtag" +msgstr "" + #: src/components/RichText.tsx:188 -msgid "Hashtag: {tag}" +#~ msgid "Hashtag: {tag}" +#~ msgstr "" + +#: src/components/RichText.tsx:190 +msgid "Hashtag: #{tag}" msgstr "" #: src/view/com/auth/create/CreateAccount.tsx:208 @@ -1780,12 +1798,13 @@ msgid "Hide" msgstr "इसे छिपाà¤à¤‚" #: src/view/com/modals/ContentFilteringSettings.tsx:224 -#: src/view/com/notifications/FeedItem.tsx:325 +#: src/view/com/notifications/FeedItem.tsx:326 msgctxt "action" msgid "Hide" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:232 +#: src/view/com/util/forms/PostDropdownBtn.tsx:276 +#: src/view/com/util/forms/PostDropdownBtn.tsx:287 msgid "Hide post" msgstr "" @@ -1794,11 +1813,11 @@ msgstr "" msgid "Hide the content" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:236 +#: src/view/com/util/forms/PostDropdownBtn.tsx:280 msgid "Hide this post?" msgstr "" -#: src/view/com/notifications/FeedItem.tsx:315 +#: src/view/com/notifications/FeedItem.tsx:316 msgid "Hide user list" msgstr "उपयोगकरà¥à¤¤à¤¾ सूची छà¥à¤ªà¤¾à¤à¤" @@ -1826,7 +1845,7 @@ msgstr "" msgid "Hmm, we're having trouble finding this feed. It may have been deleted." msgstr "" -#: src/Navigation.tsx:435 +#: src/Navigation.tsx:442 #: src/view/shell/bottom-bar/BottomBar.tsx:137 #: src/view/shell/desktop/LeftNav.tsx:306 #: src/view/shell/Drawer.tsx:398 @@ -1841,7 +1860,7 @@ msgstr "होम फीड" #~ msgid "Home Feed Preferences" #~ msgstr "होम फ़ीड पà¥à¤°à¤¾à¤¥à¤®à¤¿à¤•ताà¤à¤‚" -#: src/view/com/auth/create/Step1.tsx:82 +#: src/view/com/auth/create/Step1.tsx:75 #: src/view/com/auth/login/ForgotPasswordForm.tsx:120 msgid "Hosting provider" msgstr "होसà¥à¤Ÿà¤¿à¤‚ग पà¥à¤°à¤¦à¤¾à¤¤à¤¾" @@ -1895,11 +1914,11 @@ msgstr "" msgid "Input confirmation code for account deletion" msgstr "" -#: src/view/com/auth/create/Step1.tsx:200 +#: src/view/com/auth/create/Step1.tsx:177 msgid "Input email for Bluesky account" msgstr "" -#: src/view/com/auth/create/Step1.tsx:158 +#: src/view/com/auth/create/Step1.tsx:151 msgid "Input invite code to proceed" msgstr "" @@ -1932,8 +1951,8 @@ msgstr "" #~ msgstr "" #: src/view/com/modals/Waitlist.tsx:90 -msgid "Input your email to get on the Bluesky waitlist" -msgstr "" +#~ msgid "Input your email to get on the Bluesky waitlist" +#~ msgstr "" #: src/view/com/auth/login/LoginForm.tsx:229 msgid "Input your password" @@ -1959,8 +1978,8 @@ msgstr "अवैध उपयोगकरà¥à¤¤à¤¾ नाम या पासठmsgid "Invite a Friend" msgstr "à¤à¤• दोसà¥à¤¤ को आमंतà¥à¤°à¤¿à¤¤ करें" -#: src/view/com/auth/create/Step1.tsx:148 -#: src/view/com/auth/create/Step1.tsx:157 +#: src/view/com/auth/create/Step1.tsx:141 +#: src/view/com/auth/create/Step1.tsx:150 msgid "Invite code" msgstr "आमंतà¥à¤°à¤£ कोड" @@ -1990,17 +2009,17 @@ msgid "Jobs" msgstr "" #: src/view/com/modals/Waitlist.tsx:67 -msgid "Join the waitlist" -msgstr "पà¥à¤°à¤¤à¥€à¤•à¥à¤·à¤¾ सूची में शामिल हों" +#~ msgid "Join the waitlist" +#~ msgstr "पà¥à¤°à¤¤à¥€à¤•à¥à¤·à¤¾ सूची में शामिल हों" #: src/view/com/auth/create/Step1.tsx:174 #: src/view/com/auth/create/Step1.tsx:178 -msgid "Join the waitlist." -msgstr "पà¥à¤°à¤¤à¥€à¤•à¥à¤·à¤¾ सूची में शामिल हों।।" +#~ msgid "Join the waitlist." +#~ msgstr "पà¥à¤°à¤¤à¥€à¤•à¥à¤·à¤¾ सूची में शामिल हों।।" #: src/view/com/modals/Waitlist.tsx:128 -msgid "Join Waitlist" -msgstr "वेटरलिसà¥à¤Ÿ में शामिल हों" +#~ msgid "Join Waitlist" +#~ msgstr "वेटरलिसà¥à¤Ÿ में शामिल हों" #: src/screens/Onboarding/index.tsx:24 msgid "Journalism" @@ -2014,7 +2033,7 @@ msgstr "अपनी à¤à¤¾à¤·à¤¾ चà¥à¤¨à¥‡" msgid "Language settings" msgstr "" -#: src/Navigation.tsx:140 +#: src/Navigation.tsx:142 #: src/view/screens/LanguageSettings.tsx:89 msgid "Language Settings" msgstr "à¤à¤¾à¤·à¤¾ सेटिंगà¥à¤¸" @@ -2084,7 +2103,6 @@ msgid "Light" msgstr "लाइट मोड" #: src/view/com/util/post-ctrls/PostCtrls.tsx:182 -#: src/view/com/util/post-ctrls/PostCtrls.tsx:216 msgid "Like" msgstr "" @@ -2092,7 +2110,7 @@ msgstr "" msgid "Like this feed" msgstr "इस फ़ीड को लाइक करो" -#: src/Navigation.tsx:197 +#: src/Navigation.tsx:199 msgid "Liked by" msgstr "इन यूजर ने लाइक किया है" @@ -2125,7 +2143,7 @@ msgstr "" msgid "Likes on this post" msgstr "" -#: src/Navigation.tsx:166 +#: src/Navigation.tsx:168 msgid "List" msgstr "" @@ -2161,7 +2179,7 @@ msgstr "" msgid "List unmuted" msgstr "" -#: src/Navigation.tsx:110 +#: src/Navigation.tsx:112 #: src/view/screens/Profile.tsx:185 #: src/view/shell/desktop/LeftNav.tsx:379 #: src/view/shell/Drawer.tsx:492 @@ -2193,7 +2211,7 @@ msgstr "" #~ msgid "Local dev server" #~ msgstr "सà¥à¤¥à¤¾à¤¨à¥€à¤¯ देव सरà¥à¤µà¤°" -#: src/Navigation.tsx:207 +#: src/Navigation.tsx:209 msgid "Log" msgstr "" @@ -2216,7 +2234,7 @@ msgstr "उस खाते में लॉग इन करें जो सॠmsgid "Make sure this is where you intend to go!" msgstr "यह सà¥à¤¨à¤¿à¤¶à¥à¤šà¤¿à¤¤ करने के लिठकि आप कहाठजाना चाहते हैं!" -#: src/components/dialogs/MutedWords.tsx:71 +#: src/components/dialogs/MutedWords.tsx:83 msgid "Manage your muted words and tags" msgstr "" @@ -2240,7 +2258,7 @@ msgstr "" msgid "Mentioned users" msgstr "" -#: src/view/com/util/ViewHeader.tsx:81 +#: src/view/com/util/ViewHeader.tsx:87 #: src/view/screens/Search/Search.tsx:646 msgid "Menu" msgstr "मेनू" @@ -2249,7 +2267,7 @@ msgstr "मेनू" msgid "Message from server: {0}" msgstr "" -#: src/Navigation.tsx:115 +#: src/Navigation.tsx:117 #: src/view/screens/Moderation.tsx:66 #: src/view/screens/Settings/index.tsx:625 #: src/view/shell/desktop/LeftNav.tsx:397 @@ -2263,13 +2281,13 @@ msgstr "मॉडरेशन" msgid "Moderation list by {0}" msgstr "" -#: src/view/screens/ProfileList.tsx:774 +#: src/view/screens/ProfileList.tsx:775 msgid "Moderation list by <0/>" msgstr "" #: src/view/com/lists/ListCard.tsx:91 #: src/view/com/modals/UserAddRemoveLists.tsx:204 -#: src/view/screens/ProfileList.tsx:772 +#: src/view/screens/ProfileList.tsx:773 msgid "Moderation list by you" msgstr "" @@ -2285,7 +2303,7 @@ msgstr "" msgid "Moderation lists" msgstr "मॉडरेशन सूचियाà¤" -#: src/Navigation.tsx:120 +#: src/Navigation.tsx:122 #: src/view/screens/ModerationModlists.tsx:58 msgid "Moderation Lists" msgstr "" @@ -2298,7 +2316,7 @@ msgstr "" msgid "Moderator has chosen to set a general warning on the content." msgstr "" -#: src/view/shell/desktop/Feeds.tsx:63 +#: src/view/shell/desktop/Feeds.tsx:65 msgid "More feeds" msgstr "अधिक फ़ीड" @@ -2309,8 +2327,8 @@ msgid "More options" msgstr "अधिक विकलà¥à¤ª" #: src/view/com/util/forms/PostDropdownBtn.tsx:315 -msgid "More post options" -msgstr "पोसà¥à¤Ÿ विकलà¥à¤ª" +#~ msgid "More post options" +#~ msgstr "पोसà¥à¤Ÿ विकलà¥à¤ª" #: src/view/screens/PreferencesThreads.tsx:82 msgid "Most-liked replies first" @@ -2320,11 +2338,11 @@ msgstr "" msgid "Must be at least 3 characters" msgstr "" -#: src/components/TagMenu/index.tsx:253 +#: src/components/TagMenu/index.tsx:249 msgid "Mute" msgstr "" -#: src/components/TagMenu/index.web.tsx:91 +#: src/components/TagMenu/index.web.tsx:105 msgid "Mute {truncatedTag}" msgstr "" @@ -2336,15 +2354,19 @@ msgstr "खाता मà¥à¤¯à¥‚ट करें" msgid "Mute accounts" msgstr "खातों को मà¥à¤¯à¥‚ट करें" -#: src/components/TagMenu/index.tsx:211 -msgid "Mute all {tag} posts" +#: src/components/TagMenu/index.tsx:209 +msgid "Mute all {displayTag} posts" msgstr "" -#: src/components/dialogs/MutedWords.tsx:131 +#: src/components/TagMenu/index.tsx:211 +#~ msgid "Mute all {tag} posts" +#~ msgstr "" + +#: src/components/dialogs/MutedWords.tsx:149 msgid "Mute in tags only" msgstr "" -#: src/components/dialogs/MutedWords.tsx:116 +#: src/components/dialogs/MutedWords.tsx:134 msgid "Mute in text & tags" msgstr "" @@ -2360,19 +2382,21 @@ msgstr "इन खातों को मà¥à¤¯à¥‚ट करें?" msgid "Mute this List" msgstr "" -#: src/components/dialogs/MutedWords.tsx:109 +#: src/components/dialogs/MutedWords.tsx:127 msgid "Mute this word in post text and tags" msgstr "" -#: src/components/dialogs/MutedWords.tsx:124 +#: src/components/dialogs/MutedWords.tsx:142 msgid "Mute this word in tags only" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:202 +#: src/view/com/util/forms/PostDropdownBtn.tsx:251 +#: src/view/com/util/forms/PostDropdownBtn.tsx:257 msgid "Mute thread" msgstr "थà¥à¤°à¥‡à¤¡ मà¥à¤¯à¥‚ट करें" -#: src/view/com/util/forms/PostDropdownBtn.tsx:216 +#: src/view/com/util/forms/PostDropdownBtn.tsx:267 +#: src/view/com/util/forms/PostDropdownBtn.tsx:269 msgid "Mute words & tags" msgstr "" @@ -2384,7 +2408,7 @@ msgstr "" msgid "Muted accounts" msgstr "मà¥à¤¯à¥‚ट किठगठखाते" -#: src/Navigation.tsx:125 +#: src/Navigation.tsx:127 #: src/view/screens/ModerationMutedAccounts.tsx:107 msgid "Muted Accounts" msgstr "मà¥à¤¯à¥‚ट किठगठखाते" @@ -2460,7 +2484,7 @@ msgstr "अपने फ़ॉलोअरà¥à¤¸ और डेटा तक पà msgid "Never lose access to your followers or data." msgstr "" -#: src/components/dialogs/MutedWords.tsx:244 +#: src/components/dialogs/MutedWords.tsx:293 msgid "Nevermind" msgstr "" @@ -2548,7 +2572,7 @@ msgid "No" msgstr "नहीं" #: src/view/screens/ProfileFeed.tsx:584 -#: src/view/screens/ProfileList.tsx:754 +#: src/view/screens/ProfileList.tsx:755 msgid "No description" msgstr "कोई विवरण नहीं" @@ -2565,6 +2589,10 @@ msgstr "" msgid "No result" msgstr "" +#: src/components/Lists.tsx:192 +msgid "No results found" +msgstr "" + #: src/view/screens/Feeds.tsx:495 msgid "No results found for \"{query}\"" msgstr "\"{query}\" के लिठकोई परिणाम नहीं मिला" @@ -2587,7 +2615,7 @@ msgstr "" msgid "Not Applicable." msgstr "लागू नहीं।" -#: src/Navigation.tsx:105 +#: src/Navigation.tsx:107 #: src/view/screens/Profile.tsx:106 msgid "Not Found" msgstr "" @@ -2601,7 +2629,7 @@ msgstr "" msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites." msgstr "" -#: src/Navigation.tsx:450 +#: src/Navigation.tsx:457 #: src/view/screens/Notifications.tsx:124 #: src/view/screens/Notifications.tsx:148 #: src/view/shell/bottom-bar/BottomBar.tsx:205 @@ -2643,6 +2671,11 @@ msgstr "à¤à¤• या अधिक छवियाठalt पाठयाद ठmsgid "Only {0} can reply." msgstr "" +#: src/components/Lists.tsx:82 +msgid "Oops, something went wrong!" +msgstr "" + +#: src/components/Lists.tsx:188 #: src/view/screens/AppPasswords.tsx:65 #: src/view/screens/Profile.tsx:106 msgid "Oops!" @@ -2669,10 +2702,14 @@ msgstr "" msgid "Open muted words settings" msgstr "" -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:49 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:50 msgid "Open navigation" msgstr "ओपन नेविगेशन" +#: src/view/com/util/forms/PostDropdownBtn.tsx:175 +msgid "Open post options menu" +msgstr "" + #: src/view/screens/Settings/index.tsx:804 msgid "Open storybook page" msgstr "" @@ -2685,7 +2722,7 @@ msgstr "" msgid "Opens additional details for a debug entry" msgstr "" -#: src/view/com/notifications/FeedItem.tsx:348 +#: src/view/com/notifications/FeedItem.tsx:349 msgid "Opens an expanded list of users in this notification" msgstr "" @@ -2745,7 +2782,7 @@ msgstr "मॉडरेशन सेटिंगà¥à¤¸ खोलें" msgid "Opens password reset form" msgstr "" -#: src/view/com/home/HomeHeaderLayout.web.tsx:60 +#: src/view/com/home/HomeHeaderLayout.web.tsx:63 #: src/view/screens/Feeds.tsx:356 msgid "Opens screen to edit Saved Feeds" msgstr "" @@ -2798,6 +2835,7 @@ msgstr "अनà¥à¤¯ खाता" msgid "Other..." msgstr "अनà¥à¤¯..।" +#: src/components/Lists.tsx:194 #: src/view/screens/NotFound.tsx:45 msgid "Page not found" msgstr "पृषà¥à¤ नहीं मिला" @@ -2806,8 +2844,8 @@ msgstr "पृषà¥à¤ नहीं मिला" msgid "Page Not Found" msgstr "" -#: src/view/com/auth/create/Step1.tsx:214 -#: src/view/com/auth/create/Step1.tsx:224 +#: src/view/com/auth/create/Step1.tsx:191 +#: src/view/com/auth/create/Step1.tsx:201 #: src/view/com/auth/login/LoginForm.tsx:226 #: src/view/com/auth/login/SetNewPasswordForm.tsx:161 #: src/view/com/modals/DeleteAccount.tsx:202 @@ -2822,11 +2860,11 @@ msgstr "" msgid "Password updated!" msgstr "पासवरà¥à¤¡ अदà¥à¤¯à¤¤à¤¨!" -#: src/Navigation.tsx:160 +#: src/Navigation.tsx:162 msgid "People followed by @{0}" msgstr "" -#: src/Navigation.tsx:153 +#: src/Navigation.tsx:155 msgid "People following @{0}" msgstr "" @@ -2900,6 +2938,10 @@ msgstr "" msgid "Please enter a unique name for this App Password or use our randomly generated one." msgstr "कृपया इस à¤à¤ª पासवरà¥à¤¡ के लिठà¤à¤• अदà¥à¤µà¤¿à¤¤à¥€à¤¯ नाम दरà¥à¤œ करें या हमारे यादृचà¥à¤›à¤¿à¤• रूप से उतà¥à¤ªà¤¨à¥à¤¨ à¤à¤• का उपयोग करें।।" +#: src/components/dialogs/MutedWords.tsx:68 +msgid "Please enter a valid word, tag, or phrase to mute" +msgstr "" + #: src/view/com/auth/create/state.ts:170 #~ msgid "Please enter the code you received by SMS." #~ msgstr "" @@ -2952,13 +2994,13 @@ msgstr "पोसà¥à¤Ÿ" msgid "Post by {0}" msgstr "" -#: src/Navigation.tsx:172 -#: src/Navigation.tsx:179 -#: src/Navigation.tsx:186 +#: src/Navigation.tsx:174 +#: src/Navigation.tsx:181 +#: src/Navigation.tsx:188 msgid "Post by @{0}" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:90 +#: src/view/com/util/forms/PostDropdownBtn.tsx:108 msgid "Post deleted" msgstr "" @@ -2978,7 +3020,7 @@ msgstr "पोसà¥à¤Ÿ à¤à¤¾à¤·à¤¾" msgid "Post not found" msgstr "पोसà¥à¤Ÿ नहीं मिला" -#: src/components/TagMenu/index.tsx:257 +#: src/components/TagMenu/index.tsx:253 msgid "posts" msgstr "" @@ -2986,7 +3028,7 @@ msgstr "" msgid "Posts" msgstr "" -#: src/components/dialogs/MutedWords.tsx:77 +#: src/components/dialogs/MutedWords.tsx:90 msgid "Posts can be muted based on their text, their tags, or both." msgstr "" @@ -3015,7 +3057,7 @@ msgstr "अपने फ़ॉलोअरà¥à¤¸ को पà¥à¤°à¤¾à¤¥à¤®à¤¿à¤• msgid "Privacy" msgstr "गोपनीयता" -#: src/Navigation.tsx:217 +#: src/Navigation.tsx:219 #: src/view/screens/PrivacyPolicy.tsx:29 #: src/view/screens/Settings/index.tsx:891 #: src/view/shell/Drawer.tsx:262 @@ -3092,7 +3134,7 @@ msgstr "अनà¥à¤¶à¤‚सित फ़ीड" msgid "Recommended Users" msgstr "अनà¥à¤¶à¤‚सित लोग" -#: src/components/dialogs/MutedWords.tsx:249 +#: src/components/dialogs/MutedWords.tsx:298 #: src/view/com/modals/ListAddRemoveUsers.tsx:264 #: src/view/com/modals/SelfLabel.tsx:83 #: src/view/com/modals/UserAddRemoveLists.tsx:219 @@ -3130,7 +3172,7 @@ msgstr "छवि निकालें" msgid "Remove image preview" msgstr "छवि पूरà¥à¤µà¤¾à¤µà¤²à¥‹à¤•न निकालें" -#: src/components/dialogs/MutedWords.tsx:294 +#: src/components/dialogs/MutedWords.tsx:343 msgid "Remove mute word from your list" msgstr "" @@ -3200,7 +3242,8 @@ msgid "Report List" msgstr "रिपोरà¥à¤Ÿ सूची" #: src/view/com/modals/report/SendReportButton.tsx:37 -#: src/view/com/util/forms/PostDropdownBtn.tsx:255 +#: src/view/com/util/forms/PostDropdownBtn.tsx:301 +#: src/view/com/util/forms/PostDropdownBtn.tsx:309 msgid "Report post" msgstr "रिपोरà¥à¤Ÿ पोसà¥à¤Ÿ" @@ -3259,7 +3302,7 @@ msgstr "" msgid "Require alt text before posting" msgstr "पोसà¥à¤Ÿ करने से पहले वैकलà¥à¤ªà¤¿à¤• टेकà¥à¤¸à¥à¤Ÿ की आवशà¥à¤¯à¤•ता है" -#: src/view/com/auth/create/Step1.tsx:153 +#: src/view/com/auth/create/Step1.tsx:146 msgid "Required for this provider" msgstr "इस पà¥à¤°à¤¦à¤¾à¤¤à¤¾ के लिठआवशà¥à¤¯à¤•" @@ -3324,7 +3367,7 @@ msgstr "फिर से कोशिश करो" #~ msgid "Retry." #~ msgstr "" -#: src/view/screens/ProfileList.tsx:898 +#: src/view/screens/ProfileList.tsx:903 msgid "Return to previous page" msgstr "" @@ -3379,11 +3422,11 @@ msgstr "" msgid "Science" msgstr "" -#: src/view/screens/ProfileList.tsx:854 +#: src/view/screens/ProfileList.tsx:859 msgid "Scroll to top" msgstr "" -#: src/Navigation.tsx:440 +#: src/Navigation.tsx:447 #: src/view/com/auth/LoggedOut.tsx:122 #: src/view/com/modals/ListAddRemoveUsers.tsx:75 #: src/view/com/util/forms/SearchInput.tsx:67 @@ -3406,13 +3449,21 @@ msgid "Search for \"{query}\"" msgstr "" #: src/components/TagMenu/index.tsx:145 -msgid "Search for all posts by @{authorHandle} with tag {tag}" +msgid "Search for all posts by @{authorHandle} with tag {displayTag}" msgstr "" -#: src/components/TagMenu/index.tsx:90 -msgid "Search for all posts with tag {tag}" +#: src/components/TagMenu/index.tsx:145 +#~ msgid "Search for all posts by @{authorHandle} with tag {tag}" +#~ msgstr "" + +#: src/components/TagMenu/index.tsx:94 +msgid "Search for all posts with tag {displayTag}" msgstr "" +#: src/components/TagMenu/index.tsx:90 +#~ msgid "Search for all posts with tag {tag}" +#~ msgstr "" + #: src/view/com/auth/LoggedOut.tsx:104 #: src/view/com/auth/LoggedOut.tsx:105 #: src/view/com/modals/ListAddRemoveUsers.tsx:70 @@ -3423,22 +3474,30 @@ msgstr "" msgid "Security Step Required" msgstr "सà¥à¤°à¤•à¥à¤·à¤¾ चरण आवशà¥à¤¯à¤•" -#: src/components/TagMenu/index.web.tsx:50 +#: src/components/TagMenu/index.web.tsx:66 msgid "See {truncatedTag} posts" msgstr "" -#: src/components/TagMenu/index.web.tsx:67 +#: src/components/TagMenu/index.web.tsx:83 msgid "See {truncatedTag} posts by user" msgstr "" #: src/components/TagMenu/index.tsx:128 -msgid "See <0>{tag}</0> posts" +msgid "See <0>{displayTag}</0> posts" msgstr "" -#: src/components/TagMenu/index.tsx:189 -msgid "See <0>{tag}</0> posts by this user" +#: src/components/TagMenu/index.tsx:187 +msgid "See <0>{displayTag}</0> posts by this user" msgstr "" +#: src/components/TagMenu/index.tsx:128 +#~ msgid "See <0>{tag}</0> posts" +#~ msgstr "" + +#: src/components/TagMenu/index.tsx:189 +#~ msgid "See <0>{tag}</0> posts by this user" +#~ msgstr "" + #: src/view/screens/SavedFeeds.tsx:163 msgid "See this guide" msgstr "" @@ -3463,7 +3522,7 @@ msgstr "मौजूदा खाते से चà¥à¤¨à¥‡à¤‚" msgid "Select option {i} of {numItems}" msgstr "" -#: src/view/com/auth/create/Step1.tsx:103 +#: src/view/com/auth/create/Step1.tsx:96 #: src/view/com/auth/login/LoginForm.tsx:150 msgid "Select service" msgstr "सेवा चà¥à¤¨à¥‡à¤‚" @@ -3581,7 +3640,7 @@ msgstr "" msgid "Set new password" msgstr "नया पासवरà¥à¤¡ सेट करें" -#: src/view/com/auth/create/Step1.tsx:225 +#: src/view/com/auth/create/Step1.tsx:202 msgid "Set password" msgstr "" @@ -3625,12 +3684,12 @@ msgstr "" msgid "Sets hosting provider for password reset" msgstr "" -#: src/view/com/auth/create/Step1.tsx:104 +#: src/view/com/auth/create/Step1.tsx:97 #: src/view/com/auth/login/LoginForm.tsx:151 msgid "Sets server for the Bluesky client" msgstr "" -#: src/Navigation.tsx:135 +#: src/Navigation.tsx:137 #: src/view/screens/Settings/index.tsx:294 #: src/view/shell/desktop/LeftNav.tsx:433 #: src/view/shell/Drawer.tsx:567 @@ -3648,7 +3707,9 @@ msgid "Share" msgstr "" #: src/view/com/profile/ProfileHeader.tsx:295 -#: src/view/com/util/forms/PostDropdownBtn.tsx:184 +#: src/view/com/util/forms/PostDropdownBtn.tsx:231 +#: src/view/com/util/forms/PostDropdownBtn.tsx:237 +#: src/view/com/util/post-ctrls/PostCtrls.tsx:215 #: src/view/screens/ProfileList.tsx:418 msgid "Share" msgstr "शेयर" @@ -3740,7 +3801,7 @@ msgstr "" msgid "Show the content" msgstr "" -#: src/view/com/notifications/FeedItem.tsx:346 +#: src/view/com/notifications/FeedItem.tsx:347 msgid "Show users" msgstr "लोग दिखाà¤à¤" @@ -3847,11 +3908,15 @@ msgstr "" #~ msgid "Something went wrong and we're not sure what." #~ msgstr "" -#: src/view/com/modals/Waitlist.tsx:51 -msgid "Something went wrong. Check your email and try again." +#: src/components/Lists.tsx:203 +msgid "Something went wrong!" msgstr "" -#: src/App.native.tsx:63 +#: src/view/com/modals/Waitlist.tsx:51 +#~ msgid "Something went wrong. Check your email and try again." +#~ msgstr "" + +#: src/App.native.tsx:66 msgid "Sorry! Your session expired. Please log in again." msgstr "" @@ -3887,7 +3952,7 @@ msgstr "" msgid "Storage cleared, you need to restart the app now." msgstr "" -#: src/Navigation.tsx:202 +#: src/Navigation.tsx:204 #: src/view/screens/Settings/index.tsx:807 msgid "Storybook" msgstr "Storybook" @@ -3901,7 +3966,7 @@ msgid "Subscribe" msgstr "सबà¥à¤¸à¤•à¥à¤°à¤¾à¤‡à¤¬" #: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:173 -#: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:307 +#: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:308 msgid "Subscribe to the {0} feed" msgstr "" @@ -3921,7 +3986,7 @@ msgstr "" msgid "Suggestive" msgstr "" -#: src/Navigation.tsx:212 +#: src/Navigation.tsx:214 #: src/view/screens/Support.tsx:30 #: src/view/screens/Support.tsx:33 msgid "Support" @@ -3953,14 +4018,18 @@ msgstr "पà¥à¤°à¤£à¤¾à¤²à¥€" msgid "System log" msgstr "सिसà¥à¤Ÿà¤® लॉग" -#: src/components/dialogs/MutedWords.tsx:288 +#: src/components/dialogs/MutedWords.tsx:337 msgid "tag" msgstr "" -#: src/components/TagMenu/index.tsx:74 -msgid "Tag menu: {tag}" +#: src/components/TagMenu/index.tsx:78 +msgid "Tag menu: {displayTag}" msgstr "" +#: src/components/TagMenu/index.tsx:74 +#~ msgid "Tag menu: {tag}" +#~ msgstr "" + #: src/view/com/modals/crop-image/CropImage.web.tsx:112 msgid "Tall" msgstr "लंबा" @@ -3977,14 +4046,14 @@ msgstr "" msgid "Terms" msgstr "शरà¥à¤¤à¥‡à¤‚" -#: src/Navigation.tsx:222 +#: src/Navigation.tsx:224 #: src/view/screens/Settings/index.tsx:885 #: src/view/screens/TermsOfService.tsx:29 #: src/view/shell/Drawer.tsx:256 msgid "Terms of Service" msgstr "सेवा की शरà¥à¤¤à¥‡à¤‚" -#: src/components/dialogs/MutedWords.tsx:288 +#: src/components/dialogs/MutedWords.tsx:337 msgid "text" msgstr "" @@ -4065,7 +4134,7 @@ msgstr "" msgid "There was an issue fetching notifications. Tap here to try again." msgstr "" -#: src/view/com/posts/Feed.tsx:263 +#: src/view/com/posts/Feed.tsx:265 msgid "There was an issue fetching posts. Tap here to try again." msgstr "" @@ -4171,7 +4240,7 @@ msgstr "अगर आपको कà¤à¥€ अपना ईमेल बदलनà msgid "This link is taking you to the following website:" msgstr "यह लिंक आपको निमà¥à¤¨à¤²à¤¿à¤–ित वेबसाइट पर ले जा रहा है:" -#: src/view/screens/ProfileList.tsx:834 +#: src/view/screens/ProfileList.tsx:839 msgid "This list is empty!" msgstr "" @@ -4203,11 +4272,11 @@ msgstr "" msgid "This warning is only available for posts with media attached." msgstr "यह चेतावनी केवल मीडिया संलगà¥à¤¨ पोसà¥à¤Ÿ के लिठउपलबà¥à¤§ है।" -#: src/components/dialogs/MutedWords.tsx:236 +#: src/components/dialogs/MutedWords.tsx:285 msgid "This will delete {0} from your muted words. You can always add it back later." msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:237 +#: src/view/com/util/forms/PostDropdownBtn.tsx:282 msgid "This will hide this post from your feeds." msgstr "" @@ -4220,11 +4289,11 @@ msgstr "थà¥à¤°à¥‡à¤¡ पà¥à¤°à¤¾à¤¥à¤®à¤¿à¤•ता" msgid "Threaded Mode" msgstr "थà¥à¤°à¥‡à¤¡ मोड" -#: src/Navigation.tsx:255 +#: src/Navigation.tsx:257 msgid "Threads Preferences" msgstr "" -#: src/components/dialogs/MutedWords.tsx:95 +#: src/components/dialogs/MutedWords.tsx:113 msgid "Toggle between muted word options." msgstr "" @@ -4238,7 +4307,8 @@ msgstr "परिवरà¥à¤¤à¤¨" #: src/view/com/post-thread/PostThreadItem.tsx:685 #: src/view/com/post-thread/PostThreadItem.tsx:687 -#: src/view/com/util/forms/PostDropdownBtn.tsx:156 +#: src/view/com/util/forms/PostDropdownBtn.tsx:215 +#: src/view/com/util/forms/PostDropdownBtn.tsx:217 msgid "Translate" msgstr "अनà¥à¤µà¤¾à¤¦" @@ -4299,16 +4369,15 @@ msgid "Unfortunately, you do not meet the requirements to create an account." msgstr "" #: src/view/com/util/post-ctrls/PostCtrls.tsx:182 -#: src/view/com/util/post-ctrls/PostCtrls.tsx:216 msgid "Unlike" msgstr "" -#: src/components/TagMenu/index.tsx:253 +#: src/components/TagMenu/index.tsx:249 #: src/view/screens/ProfileList.tsx:597 msgid "Unmute" msgstr "" -#: src/components/TagMenu/index.web.tsx:90 +#: src/components/TagMenu/index.web.tsx:104 msgid "Unmute {truncatedTag}" msgstr "" @@ -4316,11 +4385,16 @@ msgstr "" msgid "Unmute Account" msgstr "अनमà¥à¤¯à¥‚ट खाता" -#: src/components/TagMenu/index.tsx:210 -msgid "Unmute all {tag} posts" +#: src/components/TagMenu/index.tsx:208 +msgid "Unmute all {displayTag} posts" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:202 +#: src/components/TagMenu/index.tsx:210 +#~ msgid "Unmute all {tag} posts" +#~ msgstr "" + +#: src/view/com/util/forms/PostDropdownBtn.tsx:251 +#: src/view/com/util/forms/PostDropdownBtn.tsx:256 msgid "Unmute thread" msgstr "थà¥à¤°à¥‡à¤¡ को अनमà¥à¤¯à¥‚ट करें" @@ -4404,13 +4478,13 @@ msgstr "यूजर हैंडल" msgid "User list by {0}" msgstr "" -#: src/view/screens/ProfileList.tsx:762 +#: src/view/screens/ProfileList.tsx:763 msgid "User list by <0/>" msgstr "" #: src/view/com/lists/ListCard.tsx:83 #: src/view/com/modals/UserAddRemoveLists.tsx:196 -#: src/view/screens/ProfileList.tsx:760 +#: src/view/screens/ProfileList.tsx:761 msgid "User list by you" msgstr "" @@ -4431,7 +4505,7 @@ msgstr "लोग सूचियाà¤" msgid "Username or email address" msgstr "यूजर नाम या ईमेल पता" -#: src/view/screens/ProfileList.tsx:796 +#: src/view/screens/ProfileList.tsx:797 msgid "Users" msgstr "यूजर लोग" @@ -4505,6 +4579,10 @@ msgstr "" msgid "We also think you'll like \"For You\" by Skygaze:" msgstr "" +#: src/screens/Hashtag.tsx:132 +msgid "We couldn't find any results for that hashtag." +msgstr "" + #: src/screens/Deactivated.tsx:133 msgid "We estimate {estimatedTime} until your account is ready." msgstr "" @@ -4521,7 +4599,7 @@ msgstr "" #~ msgid "We recommend \"For You\" by Skygaze:" #~ msgstr "" -#: src/components/dialogs/MutedWords.tsx:161 +#: src/components/dialogs/MutedWords.tsx:204 msgid "We recommend avoiding common words that appear in many posts, since it can result in no posts being shown." msgstr "" @@ -4553,7 +4631,7 @@ msgstr "हम आपके हमारी सेवा में शामिà msgid "We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @{handleOrDid}." msgstr "" -#: src/components/dialogs/MutedWords.tsx:182 +#: src/components/dialogs/MutedWords.tsx:230 msgid "We're sorry, but we weren't able to load your muted words at this time. Please try again." msgstr "" @@ -4561,6 +4639,7 @@ msgstr "" msgid "We're sorry, but your search could not be completed. Please try again in a few minutes." msgstr "" +#: src/components/Lists.tsx:211 #: src/view/screens/NotFound.tsx:48 msgid "We're sorry! We can't find the page you were looking for." msgstr "हम कà¥à¤·à¤®à¤¾ चाहते हैं! हमें वह पेज नहीं मिल रहा जिसे आप ढूंढ रहे थे।" @@ -4708,7 +4787,7 @@ msgstr "आपने अà¤à¥€ तक कोई à¤à¤ª पासवरà¥à¤¡ न msgid "You have not muted any accounts yet. To mute an account, go to their profile and selected \"Mute account\" from the menu on their account." msgstr "आपने अà¤à¥€ तक कोई खाता मà¥à¤¯à¥‚ट नहीं किया है. किसी खाते को मà¥à¤¯à¥‚ट करने के लिà¤, उनकी पà¥à¤°à¥‹à¤«à¤¼à¤¾à¤‡à¤² पर जाà¤à¤‚ और उनके खाते के मेनू से \"खाता मà¥à¤¯à¥‚ट करें\" चà¥à¤¨à¥‡à¤‚।" -#: src/components/dialogs/MutedWords.tsx:202 +#: src/components/dialogs/MutedWords.tsx:250 msgid "You haven't muted any words or tags yet" msgstr "" @@ -4720,11 +4799,11 @@ msgstr "" msgid "You must be 18 years or older to enable adult content" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:129 +#: src/view/com/util/forms/PostDropdownBtn.tsx:147 msgid "You will no longer receive notifications for this thread" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:132 +#: src/view/com/util/forms/PostDropdownBtn.tsx:150 msgid "You will now receive notifications for this thread" msgstr "" @@ -4750,7 +4829,7 @@ msgstr "" msgid "You've reached the end of your feed! Find some more accounts to follow." msgstr "" -#: src/view/com/auth/create/Step1.tsx:74 +#: src/view/com/auth/create/Step1.tsx:67 msgid "Your account" msgstr "आपका खाता" @@ -4762,7 +4841,7 @@ msgstr "" msgid "Your account repository, containing all public data records, can be downloaded as a \"CAR\" file. This file does not include media embeds, such as images, or your private data, which must be fetched separately." msgstr "" -#: src/view/com/auth/create/Step1.tsx:238 +#: src/view/com/auth/create/Step1.tsx:215 msgid "Your birth date" msgstr "जनà¥à¤® तिथि" @@ -4781,8 +4860,8 @@ msgid "Your email appears to be invalid." msgstr "" #: src/view/com/modals/Waitlist.tsx:109 -msgid "Your email has been saved! We'll be in touch soon." -msgstr "आपका ईमेल बचाया गया है! हम जलà¥à¤¦ ही संपरà¥à¤• में रहेंगे।।" +#~ msgid "Your email has been saved! We'll be in touch soon." +#~ msgstr "आपका ईमेल बचाया गया है! हम जलà¥à¤¦ ही संपरà¥à¤• में रहेंगे।।" #: src/view/com/modals/ChangeEmail.tsx:125 msgid "Your email has been updated but not verified. As a next step, please verify your new email." @@ -4810,7 +4889,7 @@ msgstr "" #~ msgid "Your invite codes are hidden when logged in using an App Password" #~ msgstr "" -#: src/components/dialogs/MutedWords.tsx:173 +#: src/components/dialogs/MutedWords.tsx:221 msgid "Your muted words" msgstr "" diff --git a/src/locale/locales/id/messages.po b/src/locale/locales/id/messages.po index 4135b9f19..69ea13bce 100644 --- a/src/locale/locales/id/messages.po +++ b/src/locale/locales/id/messages.po @@ -91,12 +91,12 @@ msgstr "Peringatan konten telah diterapkan pada {0}" msgid "A new version of the app is available. Please update to continue using the app." msgstr "Versi baru dari aplikasi ini telah tersedia. Harap perbarui untuk terus menggunakan aplikasi." -#: src/view/com/util/ViewHeader.tsx:83 +#: src/view/com/util/ViewHeader.tsx:89 #: src/view/screens/Search/Search.tsx:647 msgid "Access navigation links and settings" msgstr "Akses tautan navigasi dan pengaturan" -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:51 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:52 msgid "Access profile and other navigation links" msgstr "Akses profil dan tautan navigasi lain" @@ -143,11 +143,11 @@ msgstr "Akun batal diblokir" msgid "Account unmuted" msgstr "Akun batal dibisukan" -#: src/components/dialogs/MutedWords.tsx:147 +#: src/components/dialogs/MutedWords.tsx:165 #: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:150 #: src/view/com/modals/ListAddRemoveUsers.tsx:264 #: src/view/com/modals/UserAddRemoveLists.tsx:219 -#: src/view/screens/ProfileList.tsx:812 +#: src/view/screens/ProfileList.tsx:813 msgid "Add" msgstr "Tambah" @@ -155,7 +155,7 @@ msgstr "Tambah" msgid "Add a content warning" msgstr "Tambahkan peringatan konten" -#: src/view/screens/ProfileList.tsx:802 +#: src/view/screens/ProfileList.tsx:803 msgid "Add a user to this list" msgstr "Tambahkan pengguna ke daftar ini" @@ -193,11 +193,11 @@ msgstr "Tambahkan kartu tautan" msgid "Add link card:" msgstr "Tambahkan kartu tautan:" -#: src/components/dialogs/MutedWords.tsx:140 +#: src/components/dialogs/MutedWords.tsx:158 msgid "Add mute word for configured settings" msgstr "" -#: src/components/dialogs/MutedWords.tsx:74 +#: src/components/dialogs/MutedWords.tsx:87 msgid "Add muted words and tags" msgstr "" @@ -285,7 +285,7 @@ msgstr "Email telah dikirim ke alamat Anda sebelumnya, {0}. Email tersebut beris msgid "An issue occurred, please try again." msgstr "Terjadi masalah, silakan coba lagi." -#: src/view/com/notifications/FeedItem.tsx:236 +#: src/view/com/notifications/FeedItem.tsx:237 #: src/view/com/threadgate/WhoCanReply.tsx:178 msgid "and" msgstr "dan" @@ -318,13 +318,14 @@ msgstr "Pengaturan kata sandi aplikasi" #~ msgid "App passwords" #~ msgstr "Kata sandi aplikasi" -#: src/Navigation.tsx:237 +#: src/Navigation.tsx:239 #: src/view/screens/AppPasswords.tsx:187 #: src/view/screens/Settings/index.tsx:684 msgid "App Passwords" msgstr "Kata sandi Aplikasi" -#: src/view/com/util/forms/PostDropdownBtn.tsx:295 +#: src/view/com/util/forms/PostDropdownBtn.tsx:337 +#: src/view/com/util/forms/PostDropdownBtn.tsx:346 msgid "Appeal content warning" msgstr "Ajukan banding peringatan konten" @@ -355,12 +356,12 @@ msgstr "Anda yakin untuk menghapus kata sandi aplikasi \"{name}\"?" msgid "Are you sure you'd like to discard this draft?" msgstr "Anda yakin untuk membuang draf ini?" -#: src/components/dialogs/MutedWords.tsx:233 +#: src/components/dialogs/MutedWords.tsx:282 #: src/view/screens/ProfileList.tsx:365 msgid "Are you sure?" msgstr "Anda yakin?" -#: src/view/com/util/forms/PostDropdownBtn.tsx:278 +#: src/view/com/util/forms/PostDropdownBtn.tsx:322 msgid "Are you sure? This cannot be undone." msgstr "Anda yakin? Ini tidak dapat dibatalkan." @@ -386,7 +387,7 @@ msgstr "Ketelanjangan artistik atau non-erotis." #: src/view/com/post-thread/PostThread.tsx:522 #: src/view/com/post-thread/PostThread.tsx:530 #: src/view/com/profile/ProfileHeader.tsx:649 -#: src/view/com/util/ViewHeader.tsx:81 +#: src/view/com/util/ViewHeader.tsx:87 msgid "Back" msgstr "Kembali" @@ -403,7 +404,7 @@ msgstr "" msgid "Basics" msgstr "Dasar" -#: src/view/com/auth/create/Step1.tsx:250 +#: src/view/com/auth/create/Step1.tsx:227 #: src/view/com/modals/BirthDateSettings.tsx:73 msgid "Birthday" msgstr "Tanggal lahir" @@ -442,7 +443,7 @@ msgstr "Diblokir" msgid "Blocked accounts" msgstr "Akun yang diblokir" -#: src/Navigation.tsx:130 +#: src/Navigation.tsx:132 #: src/view/screens/ModerationBlockedAccounts.tsx:107 msgid "Blocked Accounts" msgstr "Akun yang diblokir" @@ -494,8 +495,8 @@ msgid "Bluesky is public." msgstr "Bluesky bersifat publik." #: src/view/com/modals/Waitlist.tsx:70 -msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon." -msgstr "Bluesky menggunakan undangan untuk membangun komunitas yang sehat. Jika Anda tidak tahu orang lain yang memiliki undangan, Anda bisa mendaftar di daftar tunggu dan kami akan segera mengirimkan undangannya." +#~ msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon." +#~ msgstr "Bluesky menggunakan undangan untuk membangun komunitas yang sehat. Jika Anda tidak tahu orang lain yang memiliki undangan, Anda bisa mendaftar di daftar tunggu dan kami akan segera mengirimkan undangannya." #: src/view/screens/Moderation.tsx:245 msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private." @@ -548,7 +549,7 @@ msgstr "Kamera" msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must be at least 4 characters long, but no more than 32 characters long." msgstr "Hanya dapat terdiri dari huruf, angka, spasi, tanda hubung dan garis bawah. Minimal 4 karakter, namun tidak boleh lebih dari 32 karakter." -#: src/components/Prompt.tsx:91 +#: src/components/Prompt.tsx:101 #: src/view/com/composer/Composer.tsx:307 #: src/view/com/composer/Composer.tsx:312 #: src/view/com/modals/ChangeEmail.tsx:218 @@ -563,7 +564,6 @@ msgstr "Hanya dapat terdiri dari huruf, angka, spasi, tanda hubung dan garis baw #: src/view/com/modals/Repost.tsx:87 #: src/view/com/modals/VerifyEmail.tsx:247 #: src/view/com/modals/VerifyEmail.tsx:253 -#: src/view/com/modals/Waitlist.tsx:142 #: src/view/screens/Search/Search.tsx:716 #: src/view/shell/desktop/Search.tsx:238 msgid "Cancel" @@ -608,8 +608,8 @@ msgid "Cancel search" msgstr "Batal mencari" #: src/view/com/modals/Waitlist.tsx:136 -msgid "Cancel waitlist signup" -msgstr "Batal mendaftar di daftar tunggu" +#~ msgid "Cancel waitlist signup" +#~ msgstr "Batal mendaftar di daftar tunggu" #: src/view/screens/Settings/index.tsx:334 msgctxt "action" @@ -698,7 +698,7 @@ msgstr "Pilih algoritma yang akan digunakan untuk kustom feed Anda." msgid "Choose your main feeds" msgstr "" -#: src/view/com/auth/create/Step1.tsx:219 +#: src/view/com/auth/create/Step1.tsx:196 msgid "Choose your password" msgstr "Pilih kata sandi Anda" @@ -729,11 +729,14 @@ msgstr "Hapus kueri pencarian" msgid "click here" msgstr "klik di sini" -#: src/components/RichText.tsx:189 -#: src/components/TagMenu/index.web.tsx:125 +#: src/components/TagMenu/index.web.tsx:138 msgid "Click here to open tag menu for {tag}" msgstr "" +#: src/components/RichText.tsx:191 +msgid "Click here to open tag menu for #{tag}" +msgstr "" + #: src/screens/Onboarding/index.tsx:35 msgid "Climate" msgstr "" @@ -743,8 +746,8 @@ msgstr "" msgid "Close" msgstr "" -#: src/components/Dialog/index.web.tsx:80 -#: src/components/Dialog/index.web.tsx:194 +#: src/components/Dialog/index.web.tsx:84 +#: src/components/Dialog/index.web.tsx:198 msgid "Close active dialog" msgstr "" @@ -768,7 +771,7 @@ msgstr "Tutup penampil gambar" msgid "Close navigation footer" msgstr "Tutup footer navigasi" -#: src/components/TagMenu/index.tsx:266 +#: src/components/TagMenu/index.tsx:262 msgid "Close this dialog" msgstr "" @@ -788,7 +791,7 @@ msgstr "Menutup penyusun postingan dan membuang draf" msgid "Closes viewer for header image" msgstr "Menutup penampil untuk gambar header" -#: src/view/com/notifications/FeedItem.tsx:317 +#: src/view/com/notifications/FeedItem.tsx:318 msgid "Collapses list of users for a given notification" msgstr "Menciutkan daftar pengguna untuk notifikasi tertentu" @@ -800,7 +803,7 @@ msgstr "" msgid "Comics" msgstr "" -#: src/Navigation.tsx:227 +#: src/Navigation.tsx:229 #: src/view/screens/CommunityGuidelines.tsx:32 msgid "Community Guidelines" msgstr "Panduan Komunitas" @@ -825,7 +828,7 @@ msgstr "Tulis balasan" msgid "Configure content filtering setting for category: {0}" msgstr "" -#: src/components/Prompt.tsx:113 +#: src/components/Prompt.tsx:124 #: src/view/com/modals/AppealLabel.tsx:98 #: src/view/com/modals/SelfLabel.tsx:154 #: src/view/com/modals/VerifyEmail.tsx:231 @@ -865,8 +868,8 @@ msgid "Confirmation code" msgstr "Kode konfirmasi" #: src/view/com/modals/Waitlist.tsx:120 -msgid "Confirms signing up {email} to the waitlist" -msgstr "Konfirmasi pendaftaran {email} ke daftar tunggu" +#~ msgid "Confirms signing up {email} to the waitlist" +#~ msgstr "Konfirmasi pendaftaran {email} ke daftar tunggu" #: src/view/com/auth/create/CreateAccount.tsx:193 #: src/view/com/auth/login/LoginForm.tsx:278 @@ -943,7 +946,7 @@ msgstr "Menyalin versi build ke papan klip" #: src/view/com/modals/AddAppPasswords.tsx:76 #: src/view/com/modals/InviteCodes.tsx:152 -#: src/view/com/util/forms/PostDropdownBtn.tsx:143 +#: src/view/com/util/forms/PostDropdownBtn.tsx:161 msgid "Copied to clipboard" msgstr "Disalin ke papan klip" @@ -959,7 +962,8 @@ msgstr "Salin" msgid "Copy link to list" msgstr "Salin tautan ke daftar" -#: src/view/com/util/forms/PostDropdownBtn.tsx:184 +#: src/view/com/util/forms/PostDropdownBtn.tsx:231 +#: src/view/com/util/forms/PostDropdownBtn.tsx:237 msgid "Copy link to post" msgstr "Salin tautan ke postingan" @@ -967,11 +971,12 @@ msgstr "Salin tautan ke postingan" msgid "Copy link to profile" msgstr "Salin tautan ke profil" -#: src/view/com/util/forms/PostDropdownBtn.tsx:170 +#: src/view/com/util/forms/PostDropdownBtn.tsx:223 +#: src/view/com/util/forms/PostDropdownBtn.tsx:225 msgid "Copy post text" msgstr "Salin teks postingan" -#: src/Navigation.tsx:232 +#: src/Navigation.tsx:234 #: src/view/screens/CopyrightPolicy.tsx:29 msgid "Copyright Policy" msgstr "Kebijakan Hak Cipta" @@ -980,7 +985,7 @@ msgstr "Kebijakan Hak Cipta" msgid "Could not load feed" msgstr "Tidak dapat memuat feed" -#: src/view/screens/ProfileList.tsx:888 +#: src/view/screens/ProfileList.tsx:893 msgid "Could not load list" msgstr "Tidak dapat memuat daftar" @@ -1104,11 +1109,12 @@ msgstr "Hapus akun saya" msgid "Delete My Account…" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:273 +#: src/view/com/util/forms/PostDropdownBtn.tsx:317 +#: src/view/com/util/forms/PostDropdownBtn.tsx:326 msgid "Delete post" msgstr "Hapus postingan" -#: src/view/com/util/forms/PostDropdownBtn.tsx:277 +#: src/view/com/util/forms/PostDropdownBtn.tsx:321 msgid "Delete this post?" msgstr "Hapus postingan ini?" @@ -1181,8 +1187,8 @@ msgid "Domain verified!" msgstr "Domain terverifikasi!" #: src/view/com/auth/create/Step1.tsx:170 -msgid "Don't have an invite code?" -msgstr "Tidak punya kode undangan?" +#~ msgid "Don't have an invite code?" +#~ msgstr "Tidak punya kode undangan?" #: src/view/com/auth/onboarding/RecommendedFollows.tsx:86 #: src/view/com/modals/EditImage.tsx:333 @@ -1284,7 +1290,7 @@ msgstr "Edit detail daftar" msgid "Edit Moderation List" msgstr "Ubah Daftar Moderasi" -#: src/Navigation.tsx:242 +#: src/Navigation.tsx:244 #: src/view/screens/Feeds.tsx:434 #: src/view/screens/SavedFeeds.tsx:84 msgid "Edit My Feeds" @@ -1302,7 +1308,7 @@ msgstr "Edit profil" msgid "Edit Profile" msgstr "Edit Profil" -#: src/view/com/home/HomeHeaderLayout.web.tsx:59 +#: src/view/com/home/HomeHeaderLayout.web.tsx:62 #: src/view/screens/Feeds.tsx:355 msgid "Edit Saved Feeds" msgstr "Edit Feed Tersimpan" @@ -1323,14 +1329,13 @@ msgstr "Ubah deskripsi profil Anda" msgid "Education" msgstr "" -#: src/view/com/auth/create/Step1.tsx:199 +#: src/view/com/auth/create/Step1.tsx:176 #: src/view/com/auth/login/ForgotPasswordForm.tsx:156 #: src/view/com/modals/ChangeEmail.tsx:141 -#: src/view/com/modals/Waitlist.tsx:88 msgid "Email" msgstr "Email" -#: src/view/com/auth/create/Step1.tsx:190 +#: src/view/com/auth/create/Step1.tsx:167 #: src/view/com/auth/login/ForgotPasswordForm.tsx:147 msgid "Email address" msgstr "Alamat email" @@ -1385,8 +1390,8 @@ msgstr "Akhir feed" msgid "Enter a name for this App Password" msgstr "Masukkan nama untuk Sandi Aplikasi ini" -#: src/components/dialogs/MutedWords.tsx:87 -#: src/components/dialogs/MutedWords.tsx:88 +#: src/components/dialogs/MutedWords.tsx:100 +#: src/components/dialogs/MutedWords.tsx:101 msgid "Enter a word or tag" msgstr "" @@ -1410,16 +1415,16 @@ msgstr "Masukkan domain yang ingin Anda gunakan" msgid "Enter the email you used to create your account. We'll send you a \"reset code\" so you can set a new password." msgstr "Masukkan email yang Anda gunakan untuk membuat akun. Kami akan mengirimkan \"kode reset\" untuk mengatur kata sandi baru." -#: src/view/com/auth/create/Step1.tsx:251 +#: src/view/com/auth/create/Step1.tsx:228 #: src/view/com/modals/BirthDateSettings.tsx:74 msgid "Enter your birth date" msgstr "Masukkan tanggal lahir Anda" #: src/view/com/modals/Waitlist.tsx:78 -msgid "Enter your email" -msgstr "Masukkan email Anda" +#~ msgid "Enter your email" +#~ msgstr "Masukkan email Anda" -#: src/view/com/auth/create/Step1.tsx:195 +#: src/view/com/auth/create/Step1.tsx:172 msgid "Enter your email address" msgstr "Masukkan alamat email Anda" @@ -1465,8 +1470,8 @@ msgid "Exits inputting search query" msgstr "Keluar dari memasukkan permintaan pencarian" #: src/view/com/modals/Waitlist.tsx:138 -msgid "Exits signing up for waitlist with {email}" -msgstr "Keluar dari pendaftaran untuk daftar tunggu dengan {email}" +#~ msgid "Exits signing up for waitlist with {email}" +#~ msgstr "Keluar dari pendaftaran untuk daftar tunggu dengan {email}" #: src/view/com/lightbox/Lightbox.web.tsx:163 msgid "Expand alt text" @@ -1495,7 +1500,7 @@ msgstr "Media Eksternal" msgid "External media may allow websites to collect information about you and your device. No information is sent or requested until you press the \"play\" button." msgstr "Media eksternal memungkinkan situs web untuk mengumpulkan informasi tentang Anda dan perangkat Anda. Tidak ada informasi yang dikirim atau diminta hingga Anda menekan tombol \"play\"." -#: src/Navigation.tsx:261 +#: src/Navigation.tsx:263 #: src/view/screens/PreferencesExternalEmbeds.tsx:52 #: src/view/screens/Settings/index.tsx:657 msgid "External Media Preferences" @@ -1514,7 +1519,7 @@ msgstr "Gagal membuat kata sandi aplikasi." msgid "Failed to create the list. Check your internet connection and try again." msgstr "Gagal membuat daftar. Periksa koneksi internet Anda dan coba lagi." -#: src/view/com/util/forms/PostDropdownBtn.tsx:110 +#: src/view/com/util/forms/PostDropdownBtn.tsx:128 msgid "Failed to delete post, please try again" msgstr "Gagal menghapus postingan, silakan coba lagi" @@ -1523,7 +1528,7 @@ msgstr "Gagal menghapus postingan, silakan coba lagi" msgid "Failed to load recommended feeds" msgstr "Gagal memuat rekomendasi feed" -#: src/Navigation.tsx:192 +#: src/Navigation.tsx:194 msgid "Feed" msgstr "Feed" @@ -1544,7 +1549,7 @@ msgstr "Feed offline" msgid "Feedback" msgstr "Masukan" -#: src/Navigation.tsx:445 +#: src/Navigation.tsx:452 #: src/view/screens/Feeds.tsx:419 #: src/view/screens/Feeds.tsx:524 #: src/view/screens/Profile.tsx:184 @@ -1692,9 +1697,9 @@ msgstr "Mengikuti" msgid "Following {0}" msgstr "Mengikuti {0}" -#: src/Navigation.tsx:248 -#: src/view/com/home/HomeHeaderLayout.web.tsx:45 -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:83 +#: src/Navigation.tsx:250 +#: src/view/com/home/HomeHeaderLayout.web.tsx:50 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:84 #: src/view/screens/PreferencesFollowingFeed.tsx:104 #: src/view/screens/Settings/index.tsx:543 msgid "Following Feed Preferences" @@ -1733,6 +1738,11 @@ msgstr "Lupa kata sandi" msgid "Forgot Password" msgstr "Lupa Kata Sandi" +#: src/screens/Hashtag.tsx:108 +#: src/screens/Hashtag.tsx:148 +msgid "From @{sanitizedAuthor}" +msgstr "" + #: src/view/com/posts/FeedItem.tsx:189 msgctxt "from-feed" msgid "From <0/>" @@ -1756,8 +1766,8 @@ msgstr "Kembali" #: src/view/screens/ProfileFeed.tsx:106 #: src/view/screens/ProfileFeed.tsx:111 -#: src/view/screens/ProfileList.tsx:897 #: src/view/screens/ProfileList.tsx:902 +#: src/view/screens/ProfileList.tsx:907 msgid "Go Back" msgstr "Kembali" @@ -1783,8 +1793,16 @@ msgstr "Berikutnya" msgid "Handle" msgstr "Handle" +#: src/Navigation.tsx:270 +msgid "Hashtag" +msgstr "" + #: src/components/RichText.tsx:188 -msgid "Hashtag: {tag}" +#~ msgid "Hashtag: {tag}" +#~ msgstr "" + +#: src/components/RichText.tsx:190 +msgid "Hashtag: #{tag}" msgstr "" #: src/view/com/auth/create/CreateAccount.tsx:208 @@ -1824,12 +1842,13 @@ msgid "Hide" msgstr "Sembunyikan" #: src/view/com/modals/ContentFilteringSettings.tsx:224 -#: src/view/com/notifications/FeedItem.tsx:325 +#: src/view/com/notifications/FeedItem.tsx:326 msgctxt "action" msgid "Hide" msgstr "Sembunyikan" -#: src/view/com/util/forms/PostDropdownBtn.tsx:232 +#: src/view/com/util/forms/PostDropdownBtn.tsx:276 +#: src/view/com/util/forms/PostDropdownBtn.tsx:287 msgid "Hide post" msgstr "Sembunyikan postingan" @@ -1838,11 +1857,11 @@ msgstr "Sembunyikan postingan" msgid "Hide the content" msgstr "Sembunyikan konten" -#: src/view/com/util/forms/PostDropdownBtn.tsx:236 +#: src/view/com/util/forms/PostDropdownBtn.tsx:280 msgid "Hide this post?" msgstr "Sembunyikan postingan ini?" -#: src/view/com/notifications/FeedItem.tsx:315 +#: src/view/com/notifications/FeedItem.tsx:316 msgid "Hide user list" msgstr "Sembunyikan daftar pengguna" @@ -1870,7 +1889,7 @@ msgstr "Hmm, server feed memberikan respons yang buruk. Harap beri tahu pemilik msgid "Hmm, we're having trouble finding this feed. It may have been deleted." msgstr "Hmm, kami kesulitan menemukan feed ini. Mungkin sudah dihapus." -#: src/Navigation.tsx:435 +#: src/Navigation.tsx:442 #: src/view/shell/bottom-bar/BottomBar.tsx:137 #: src/view/shell/desktop/LeftNav.tsx:306 #: src/view/shell/Drawer.tsx:398 @@ -1885,7 +1904,7 @@ msgstr "Beranda" #~ msgid "Home Feed Preferences" #~ msgstr "Preferensi Feed Beranda" -#: src/view/com/auth/create/Step1.tsx:82 +#: src/view/com/auth/create/Step1.tsx:75 #: src/view/com/auth/login/ForgotPasswordForm.tsx:120 msgid "Hosting provider" msgstr "Provider hosting" @@ -1943,7 +1962,7 @@ msgstr "Masukkan kode yang dikirim ke email Anda untuk pengaturan ulang kata san msgid "Input confirmation code for account deletion" msgstr "Masukkan kode konfirmasi untuk penghapusan akun" -#: src/view/com/auth/create/Step1.tsx:200 +#: src/view/com/auth/create/Step1.tsx:177 msgid "Input email for Bluesky account" msgstr "" @@ -1955,7 +1974,7 @@ msgstr "" #~ msgid "Input hosting provider address" #~ msgstr "Masukkan alamat penyedia hosting" -#: src/view/com/auth/create/Step1.tsx:158 +#: src/view/com/auth/create/Step1.tsx:151 msgid "Input invite code to proceed" msgstr "Masukkan kode undangan untuk melanjutkan" @@ -1988,8 +2007,8 @@ msgstr "Masukkan nama pengguna atau alamat email yang Anda gunakan saat mendafta #~ msgstr "" #: src/view/com/modals/Waitlist.tsx:90 -msgid "Input your email to get on the Bluesky waitlist" -msgstr "Masukkan email Anda untuk masuk ke daftar tunggu Bluesky" +#~ msgid "Input your email to get on the Bluesky waitlist" +#~ msgstr "Masukkan email Anda untuk masuk ke daftar tunggu Bluesky" #: src/view/com/auth/login/LoginForm.tsx:229 msgid "Input your password" @@ -2015,8 +2034,8 @@ msgstr "Username atau kata sandi salah" msgid "Invite a Friend" msgstr "Undang Teman" -#: src/view/com/auth/create/Step1.tsx:148 -#: src/view/com/auth/create/Step1.tsx:157 +#: src/view/com/auth/create/Step1.tsx:141 +#: src/view/com/auth/create/Step1.tsx:150 msgid "Invite code" msgstr "Kode Undangan" @@ -2046,17 +2065,17 @@ msgid "Jobs" msgstr "Karir" #: src/view/com/modals/Waitlist.tsx:67 -msgid "Join the waitlist" -msgstr "Gabung ke daftar tunggu" +#~ msgid "Join the waitlist" +#~ msgstr "Gabung ke daftar tunggu" #: src/view/com/auth/create/Step1.tsx:174 #: src/view/com/auth/create/Step1.tsx:178 -msgid "Join the waitlist." -msgstr "Gabung ke daftar tunggu." +#~ msgid "Join the waitlist." +#~ msgstr "Gabung ke daftar tunggu." #: src/view/com/modals/Waitlist.tsx:128 -msgid "Join Waitlist" -msgstr "Gabung ke Daftar Tunggu" +#~ msgid "Join Waitlist" +#~ msgstr "Gabung ke Daftar Tunggu" #: src/screens/Onboarding/index.tsx:24 msgid "Journalism" @@ -2070,7 +2089,7 @@ msgstr "Pilih bahasa" msgid "Language settings" msgstr "Pengaturan bahasa" -#: src/Navigation.tsx:140 +#: src/Navigation.tsx:142 #: src/view/screens/LanguageSettings.tsx:89 msgid "Language Settings" msgstr "Pengaturan Bahasa" @@ -2140,7 +2159,6 @@ msgid "Light" msgstr "Terang" #: src/view/com/util/post-ctrls/PostCtrls.tsx:182 -#: src/view/com/util/post-ctrls/PostCtrls.tsx:216 msgid "Like" msgstr "Suka" @@ -2148,7 +2166,7 @@ msgstr "Suka" msgid "Like this feed" msgstr "Suka feed ini" -#: src/Navigation.tsx:197 +#: src/Navigation.tsx:199 msgid "Liked by" msgstr "Disukai oleh" @@ -2189,7 +2207,7 @@ msgstr "Suka" msgid "Likes on this post" msgstr "Suka pada postingan ini" -#: src/Navigation.tsx:166 +#: src/Navigation.tsx:168 msgid "List" msgstr "Daftar" @@ -2225,7 +2243,7 @@ msgstr "Daftar tidak diblokir" msgid "List unmuted" msgstr "Daftar tidak dibisukan" -#: src/Navigation.tsx:110 +#: src/Navigation.tsx:112 #: src/view/screens/Profile.tsx:185 #: src/view/shell/desktop/LeftNav.tsx:379 #: src/view/shell/Drawer.tsx:492 @@ -2257,7 +2275,7 @@ msgstr "Memuat..." #~ msgid "Local dev server" #~ msgstr "Server dev lokal" -#: src/Navigation.tsx:207 +#: src/Navigation.tsx:209 msgid "Log" msgstr "Catatan" @@ -2283,7 +2301,7 @@ msgstr "Masuk ke akun yang tidak ada di daftar" msgid "Make sure this is where you intend to go!" msgstr "Pastikan ini adalah website yang Anda tuju!" -#: src/components/dialogs/MutedWords.tsx:71 +#: src/components/dialogs/MutedWords.tsx:83 msgid "Manage your muted words and tags" msgstr "" @@ -2307,7 +2325,7 @@ msgstr "pengguna yang disebutkan" msgid "Mentioned users" msgstr "Pengguna yang disebutkan" -#: src/view/com/util/ViewHeader.tsx:81 +#: src/view/com/util/ViewHeader.tsx:87 #: src/view/screens/Search/Search.tsx:646 msgid "Menu" msgstr "Menu" @@ -2319,7 +2337,7 @@ msgstr "Menu" msgid "Message from server: {0}" msgstr "Pesan dari server: {0}" -#: src/Navigation.tsx:115 +#: src/Navigation.tsx:117 #: src/view/screens/Moderation.tsx:66 #: src/view/screens/Settings/index.tsx:625 #: src/view/shell/desktop/LeftNav.tsx:397 @@ -2333,13 +2351,13 @@ msgstr "Moderasi" msgid "Moderation list by {0}" msgstr "Daftar moderasi oleh {0}" -#: src/view/screens/ProfileList.tsx:774 +#: src/view/screens/ProfileList.tsx:775 msgid "Moderation list by <0/>" msgstr "Daftar moderasi oleh <0/>" #: src/view/com/lists/ListCard.tsx:91 #: src/view/com/modals/UserAddRemoveLists.tsx:204 -#: src/view/screens/ProfileList.tsx:772 +#: src/view/screens/ProfileList.tsx:773 msgid "Moderation list by you" msgstr "Daftar moderasi oleh Anda" @@ -2355,7 +2373,7 @@ msgstr "Daftar moderasi diperbarui" msgid "Moderation lists" msgstr "Daftar moderasi" -#: src/Navigation.tsx:120 +#: src/Navigation.tsx:122 #: src/view/screens/ModerationModlists.tsx:58 msgid "Moderation Lists" msgstr "Daftar Moderasi" @@ -2368,7 +2386,7 @@ msgstr "Pengaturan moderasi" msgid "Moderator has chosen to set a general warning on the content." msgstr "Moderator telah memilih untuk menetapkan peringatan umum pada konten." -#: src/view/shell/desktop/Feeds.tsx:63 +#: src/view/shell/desktop/Feeds.tsx:65 msgid "More feeds" msgstr "Feed lainnya" @@ -2379,8 +2397,8 @@ msgid "More options" msgstr "Pilihan lainnya" #: src/view/com/util/forms/PostDropdownBtn.tsx:315 -msgid "More post options" -msgstr "Opsi posting lainnya" +#~ msgid "More post options" +#~ msgstr "Opsi posting lainnya" #: src/view/screens/PreferencesThreads.tsx:82 msgid "Most-liked replies first" @@ -2390,11 +2408,11 @@ msgstr "Balasan yang paling disukai lebih dulu" msgid "Must be at least 3 characters" msgstr "" -#: src/components/TagMenu/index.tsx:253 +#: src/components/TagMenu/index.tsx:249 msgid "Mute" msgstr "" -#: src/components/TagMenu/index.web.tsx:91 +#: src/components/TagMenu/index.web.tsx:105 msgid "Mute {truncatedTag}" msgstr "" @@ -2406,15 +2424,19 @@ msgstr "Bisukan Akun" msgid "Mute accounts" msgstr "Bisukan akun" -#: src/components/TagMenu/index.tsx:211 -msgid "Mute all {tag} posts" +#: src/components/TagMenu/index.tsx:209 +msgid "Mute all {displayTag} posts" msgstr "" -#: src/components/dialogs/MutedWords.tsx:131 +#: src/components/TagMenu/index.tsx:211 +#~ msgid "Mute all {tag} posts" +#~ msgstr "" + +#: src/components/dialogs/MutedWords.tsx:149 msgid "Mute in tags only" msgstr "" -#: src/components/dialogs/MutedWords.tsx:116 +#: src/components/dialogs/MutedWords.tsx:134 msgid "Mute in text & tags" msgstr "" @@ -2430,19 +2452,21 @@ msgstr "Bisukan akun ini?" msgid "Mute this List" msgstr "Bisukan Daftar ini" -#: src/components/dialogs/MutedWords.tsx:109 +#: src/components/dialogs/MutedWords.tsx:127 msgid "Mute this word in post text and tags" msgstr "" -#: src/components/dialogs/MutedWords.tsx:124 +#: src/components/dialogs/MutedWords.tsx:142 msgid "Mute this word in tags only" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:202 +#: src/view/com/util/forms/PostDropdownBtn.tsx:251 +#: src/view/com/util/forms/PostDropdownBtn.tsx:257 msgid "Mute thread" msgstr "Bisukan utasan" -#: src/view/com/util/forms/PostDropdownBtn.tsx:216 +#: src/view/com/util/forms/PostDropdownBtn.tsx:267 +#: src/view/com/util/forms/PostDropdownBtn.tsx:269 msgid "Mute words & tags" msgstr "" @@ -2454,7 +2478,7 @@ msgstr "Dibisukan" msgid "Muted accounts" msgstr "Akun yang dibisukan" -#: src/Navigation.tsx:125 +#: src/Navigation.tsx:127 #: src/view/screens/ModerationMutedAccounts.tsx:107 msgid "Muted Accounts" msgstr "Akun yang Dibisukan" @@ -2530,7 +2554,7 @@ msgstr "Tidak akan lagi kehilangan akses ke data dan pengikut Anda." msgid "Never lose access to your followers or data." msgstr "" -#: src/components/dialogs/MutedWords.tsx:244 +#: src/components/dialogs/MutedWords.tsx:293 msgid "Nevermind" msgstr "" @@ -2621,7 +2645,7 @@ msgid "No" msgstr "Tidak" #: src/view/screens/ProfileFeed.tsx:584 -#: src/view/screens/ProfileList.tsx:754 +#: src/view/screens/ProfileList.tsx:755 msgid "No description" msgstr "Tidak ada deskripsi" @@ -2638,6 +2662,10 @@ msgstr "Belum ada notifikasi!" msgid "No result" msgstr "Tidak ada hasil" +#: src/components/Lists.tsx:192 +msgid "No results found" +msgstr "" + #: src/view/screens/Feeds.tsx:495 msgid "No results found for \"{query}\"" msgstr "Tidak ada hasil ditemukan untuk \"{query}\"" @@ -2660,7 +2688,7 @@ msgstr "Tak seorang pun" msgid "Not Applicable." msgstr "Tidak Berlaku." -#: src/Navigation.tsx:105 +#: src/Navigation.tsx:107 #: src/view/screens/Profile.tsx:106 msgid "Not Found" msgstr "Tidak ditemukan" @@ -2674,7 +2702,7 @@ msgstr "Jangan sekarang" msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites." msgstr "Catatan: Bluesky merupakan jaringan terbuka dan publik. Pengaturan ini hanya akan membatasi visibilitas konten Anda pada aplikasi dan website Bluesky, dan aplikasi lain mungkin tidak mengindahkan pengaturan ini. Konten Anda mungkin tetap ditampilkan kepada pengguna yang tidak login oleh aplikasi dan website lain." -#: src/Navigation.tsx:450 +#: src/Navigation.tsx:457 #: src/view/screens/Notifications.tsx:124 #: src/view/screens/Notifications.tsx:148 #: src/view/shell/bottom-bar/BottomBar.tsx:205 @@ -2716,6 +2744,11 @@ msgstr "Satu atau lebih gambar belum ada teks alt." msgid "Only {0} can reply." msgstr "Hanya {0} dapat membalas." +#: src/components/Lists.tsx:82 +msgid "Oops, something went wrong!" +msgstr "" + +#: src/components/Lists.tsx:188 #: src/view/screens/AppPasswords.tsx:65 #: src/view/screens/Profile.tsx:106 msgid "Oops!" @@ -2742,10 +2775,14 @@ msgstr "Buka tautan dengan browser dalam aplikasi" msgid "Open muted words settings" msgstr "" -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:49 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:50 msgid "Open navigation" msgstr "Buka navigasi" +#: src/view/com/util/forms/PostDropdownBtn.tsx:175 +msgid "Open post options menu" +msgstr "" + #: src/view/screens/Settings/index.tsx:804 msgid "Open storybook page" msgstr "Buka halaman buku cerita" @@ -2758,7 +2795,7 @@ msgstr "Membuka opsi {numItems}" msgid "Opens additional details for a debug entry" msgstr "Membuka detail tambahan untuk entri debug" -#: src/view/com/notifications/FeedItem.tsx:348 +#: src/view/com/notifications/FeedItem.tsx:349 msgid "Opens an expanded list of users in this notification" msgstr "Membuka daftar pengguna yang diperluas dalam notifikasi ini" @@ -2818,7 +2855,7 @@ msgstr "Buka pengaturan moderasi" msgid "Opens password reset form" msgstr "Membuka formulir pengaturan ulang kata sandi" -#: src/view/com/home/HomeHeaderLayout.web.tsx:60 +#: src/view/com/home/HomeHeaderLayout.web.tsx:63 #: src/view/screens/Feeds.tsx:356 msgid "Opens screen to edit Saved Feeds" msgstr "Membuka layar untuk mengedit Umpan Tersimpan" @@ -2871,6 +2908,7 @@ msgstr "Akun lainnya" msgid "Other..." msgstr "Lainnya..." +#: src/components/Lists.tsx:194 #: src/view/screens/NotFound.tsx:45 msgid "Page not found" msgstr "Halaman tidak ditemukan" @@ -2879,8 +2917,8 @@ msgstr "Halaman tidak ditemukan" msgid "Page Not Found" msgstr "" -#: src/view/com/auth/create/Step1.tsx:214 -#: src/view/com/auth/create/Step1.tsx:224 +#: src/view/com/auth/create/Step1.tsx:191 +#: src/view/com/auth/create/Step1.tsx:201 #: src/view/com/auth/login/LoginForm.tsx:226 #: src/view/com/auth/login/SetNewPasswordForm.tsx:161 #: src/view/com/modals/DeleteAccount.tsx:202 @@ -2895,11 +2933,11 @@ msgstr "Kata sandi diganti" msgid "Password updated!" msgstr "Kata sandi diganti!" -#: src/Navigation.tsx:160 +#: src/Navigation.tsx:162 msgid "People followed by @{0}" msgstr "Orang yang diikuti oleh @{0}" -#: src/Navigation.tsx:153 +#: src/Navigation.tsx:155 msgid "People following @{0}" msgstr "Orang yang mengikuti @{0}" @@ -2973,6 +3011,10 @@ msgstr "Masukkan nama untuk kata sandi aplikasi Anda. Semua spasi tidak diperbol msgid "Please enter a unique name for this App Password or use our randomly generated one." msgstr "Masukkan nama unik untuk Kata Sandi Aplikasi ini atau gunakan nama yang dibuat secara acak." +#: src/components/dialogs/MutedWords.tsx:68 +msgid "Please enter a valid word, tag, or phrase to mute" +msgstr "" + #: src/view/com/auth/create/state.ts:170 #~ msgid "Please enter the code you received by SMS." #~ msgstr "" @@ -3031,13 +3073,13 @@ msgstr "Posting" msgid "Post by {0}" msgstr "Postingan oleh {0}" -#: src/Navigation.tsx:172 -#: src/Navigation.tsx:179 -#: src/Navigation.tsx:186 +#: src/Navigation.tsx:174 +#: src/Navigation.tsx:181 +#: src/Navigation.tsx:188 msgid "Post by @{0}" msgstr "Postingan oleh @{0}" -#: src/view/com/util/forms/PostDropdownBtn.tsx:90 +#: src/view/com/util/forms/PostDropdownBtn.tsx:108 msgid "Post deleted" msgstr "Postingan dihapus" @@ -3057,7 +3099,7 @@ msgstr "Bahasa Postingan" msgid "Post not found" msgstr "Postingan tidak ditemukan" -#: src/components/TagMenu/index.tsx:257 +#: src/components/TagMenu/index.tsx:253 msgid "posts" msgstr "" @@ -3065,7 +3107,7 @@ msgstr "" msgid "Posts" msgstr "Postingan" -#: src/components/dialogs/MutedWords.tsx:77 +#: src/components/dialogs/MutedWords.tsx:90 msgid "Posts can be muted based on their text, their tags, or both." msgstr "" @@ -3094,7 +3136,7 @@ msgstr "Prioritaskan Pengikut Anda" msgid "Privacy" msgstr "Privasi" -#: src/Navigation.tsx:217 +#: src/Navigation.tsx:219 #: src/view/screens/PrivacyPolicy.tsx:29 #: src/view/screens/Settings/index.tsx:891 #: src/view/shell/Drawer.tsx:262 @@ -3174,7 +3216,7 @@ msgstr "Feed Direkomendasikan" msgid "Recommended Users" msgstr "Pengguna Direkomendasikan" -#: src/components/dialogs/MutedWords.tsx:249 +#: src/components/dialogs/MutedWords.tsx:298 #: src/view/com/modals/ListAddRemoveUsers.tsx:264 #: src/view/com/modals/SelfLabel.tsx:83 #: src/view/com/modals/UserAddRemoveLists.tsx:219 @@ -3212,7 +3254,7 @@ msgstr "Hapus gambar" msgid "Remove image preview" msgstr "Hapus pratinjau gambar" -#: src/components/dialogs/MutedWords.tsx:294 +#: src/components/dialogs/MutedWords.tsx:343 msgid "Remove mute word from your list" msgstr "" @@ -3282,7 +3324,8 @@ msgid "Report List" msgstr "Laporkan Daftar" #: src/view/com/modals/report/SendReportButton.tsx:37 -#: src/view/com/util/forms/PostDropdownBtn.tsx:255 +#: src/view/com/util/forms/PostDropdownBtn.tsx:301 +#: src/view/com/util/forms/PostDropdownBtn.tsx:309 msgid "Report post" msgstr "Laporkan postingan" @@ -3349,7 +3392,7 @@ msgstr "" msgid "Require alt text before posting" msgstr "Memerlukan teks alt sebelum memposting" -#: src/view/com/auth/create/Step1.tsx:153 +#: src/view/com/auth/create/Step1.tsx:146 msgid "Required for this provider" msgstr "Diwajibkan untuk provider ini" @@ -3414,7 +3457,7 @@ msgstr "Ulangi" #~ msgid "Retry." #~ msgstr "" -#: src/view/screens/ProfileList.tsx:898 +#: src/view/screens/ProfileList.tsx:903 msgid "Return to previous page" msgstr "Kembali ke halaman sebelumnya" @@ -3469,11 +3512,11 @@ msgstr "Simpan perubahan handle ke {handle}" msgid "Science" msgstr "" -#: src/view/screens/ProfileList.tsx:854 +#: src/view/screens/ProfileList.tsx:859 msgid "Scroll to top" msgstr "Gulir ke atas" -#: src/Navigation.tsx:440 +#: src/Navigation.tsx:447 #: src/view/com/auth/LoggedOut.tsx:122 #: src/view/com/modals/ListAddRemoveUsers.tsx:75 #: src/view/com/util/forms/SearchInput.tsx:67 @@ -3496,13 +3539,21 @@ msgid "Search for \"{query}\"" msgstr "" #: src/components/TagMenu/index.tsx:145 -msgid "Search for all posts by @{authorHandle} with tag {tag}" +msgid "Search for all posts by @{authorHandle} with tag {displayTag}" msgstr "" -#: src/components/TagMenu/index.tsx:90 -msgid "Search for all posts with tag {tag}" +#: src/components/TagMenu/index.tsx:145 +#~ msgid "Search for all posts by @{authorHandle} with tag {tag}" +#~ msgstr "" + +#: src/components/TagMenu/index.tsx:94 +msgid "Search for all posts with tag {displayTag}" msgstr "" +#: src/components/TagMenu/index.tsx:90 +#~ msgid "Search for all posts with tag {tag}" +#~ msgstr "" + #: src/view/com/auth/LoggedOut.tsx:104 #: src/view/com/auth/LoggedOut.tsx:105 #: src/view/com/modals/ListAddRemoveUsers.tsx:70 @@ -3513,22 +3564,30 @@ msgstr "Cari pengguna" msgid "Security Step Required" msgstr "Langkah Keamanan Diperlukan" -#: src/components/TagMenu/index.web.tsx:50 +#: src/components/TagMenu/index.web.tsx:66 msgid "See {truncatedTag} posts" msgstr "" -#: src/components/TagMenu/index.web.tsx:67 +#: src/components/TagMenu/index.web.tsx:83 msgid "See {truncatedTag} posts by user" msgstr "" #: src/components/TagMenu/index.tsx:128 -msgid "See <0>{tag}</0> posts" +msgid "See <0>{displayTag}</0> posts" msgstr "" -#: src/components/TagMenu/index.tsx:189 -msgid "See <0>{tag}</0> posts by this user" +#: src/components/TagMenu/index.tsx:187 +msgid "See <0>{displayTag}</0> posts by this user" msgstr "" +#: src/components/TagMenu/index.tsx:128 +#~ msgid "See <0>{tag}</0> posts" +#~ msgstr "" + +#: src/components/TagMenu/index.tsx:189 +#~ msgid "See <0>{tag}</0> posts by this user" +#~ msgstr "" + #: src/view/screens/SavedFeeds.tsx:163 msgid "See this guide" msgstr "Lihat panduan ini" @@ -3553,7 +3612,7 @@ msgstr "Pilih dari akun yang sudah ada" msgid "Select option {i} of {numItems}" msgstr "Pilih opsi {i} dari {numItems}" -#: src/view/com/auth/create/Step1.tsx:103 +#: src/view/com/auth/create/Step1.tsx:96 #: src/view/com/auth/login/LoginForm.tsx:150 msgid "Select service" msgstr "Pilih layanan" @@ -3674,7 +3733,7 @@ msgstr "" msgid "Set new password" msgstr "Buat kata sandi baru" -#: src/view/com/auth/create/Step1.tsx:225 +#: src/view/com/auth/create/Step1.tsx:202 msgid "Set password" msgstr "Atur kata sandi" @@ -3722,12 +3781,12 @@ msgstr "Atur penyedia hosting untuk pengaturan ulang kata sandi" #~ msgid "Sets hosting provider to {label}" #~ msgstr "Atur penyedia hosting ke {label}" -#: src/view/com/auth/create/Step1.tsx:104 +#: src/view/com/auth/create/Step1.tsx:97 #: src/view/com/auth/login/LoginForm.tsx:151 msgid "Sets server for the Bluesky client" msgstr "Atur server untuk klien Bluesky" -#: src/Navigation.tsx:135 +#: src/Navigation.tsx:137 #: src/view/screens/Settings/index.tsx:294 #: src/view/shell/desktop/LeftNav.tsx:433 #: src/view/shell/Drawer.tsx:567 @@ -3745,7 +3804,9 @@ msgid "Share" msgstr "Bagikan" #: src/view/com/profile/ProfileHeader.tsx:295 -#: src/view/com/util/forms/PostDropdownBtn.tsx:184 +#: src/view/com/util/forms/PostDropdownBtn.tsx:231 +#: src/view/com/util/forms/PostDropdownBtn.tsx:237 +#: src/view/com/util/post-ctrls/PostCtrls.tsx:215 #: src/view/screens/ProfileList.tsx:418 msgid "Share" msgstr "Bagikan" @@ -3837,7 +3898,7 @@ msgstr "" msgid "Show the content" msgstr "Tampilkan konten" -#: src/view/com/notifications/FeedItem.tsx:346 +#: src/view/com/notifications/FeedItem.tsx:347 msgid "Show users" msgstr "Tampilkan pengguna" @@ -3944,11 +4005,15 @@ msgstr "" #~ msgid "Something went wrong and we're not sure what." #~ msgstr "Ada yang tidak beres dan kami tidak yakin apa itu." +#: src/components/Lists.tsx:203 +msgid "Something went wrong!" +msgstr "" + #: src/view/com/modals/Waitlist.tsx:51 -msgid "Something went wrong. Check your email and try again." -msgstr "Ada yang tidak beres. Periksa email Anda dan coba lagi." +#~ msgid "Something went wrong. Check your email and try again." +#~ msgstr "Ada yang tidak beres. Periksa email Anda dan coba lagi." -#: src/App.native.tsx:63 +#: src/App.native.tsx:66 msgid "Sorry! Your session expired. Please log in again." msgstr "Maaf! Sesi Anda telah berakhir. Silakan masuk lagi." @@ -3988,7 +4053,7 @@ msgstr "" msgid "Storage cleared, you need to restart the app now." msgstr "Penyimpanan dihapus, Anda perlu memulai ulang aplikasi sekarang." -#: src/Navigation.tsx:202 +#: src/Navigation.tsx:204 #: src/view/screens/Settings/index.tsx:807 msgid "Storybook" msgstr "Storybook" @@ -4002,7 +4067,7 @@ msgid "Subscribe" msgstr "Langganan" #: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:173 -#: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:307 +#: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:308 msgid "Subscribe to the {0} feed" msgstr "" @@ -4022,7 +4087,7 @@ msgstr "Disarankan untuk Anda" msgid "Suggestive" msgstr "Sugestif" -#: src/Navigation.tsx:212 +#: src/Navigation.tsx:214 #: src/view/screens/Support.tsx:30 #: src/view/screens/Support.tsx:33 msgid "Support" @@ -4054,14 +4119,18 @@ msgstr "Sistem" msgid "System log" msgstr "Log sistem" -#: src/components/dialogs/MutedWords.tsx:288 +#: src/components/dialogs/MutedWords.tsx:337 msgid "tag" msgstr "" -#: src/components/TagMenu/index.tsx:74 -msgid "Tag menu: {tag}" +#: src/components/TagMenu/index.tsx:78 +msgid "Tag menu: {displayTag}" msgstr "" +#: src/components/TagMenu/index.tsx:74 +#~ msgid "Tag menu: {tag}" +#~ msgstr "" + #: src/view/com/modals/crop-image/CropImage.web.tsx:112 msgid "Tall" msgstr "Tinggi" @@ -4078,14 +4147,14 @@ msgstr "" msgid "Terms" msgstr "Ketentuan" -#: src/Navigation.tsx:222 +#: src/Navigation.tsx:224 #: src/view/screens/Settings/index.tsx:885 #: src/view/screens/TermsOfService.tsx:29 #: src/view/shell/Drawer.tsx:256 msgid "Terms of Service" msgstr "Ketentuan Layanan" -#: src/components/dialogs/MutedWords.tsx:288 +#: src/components/dialogs/MutedWords.tsx:337 msgid "text" msgstr "" @@ -4169,7 +4238,7 @@ msgstr "Ada masalah saat menghubungi server Anda" msgid "There was an issue fetching notifications. Tap here to try again." msgstr "Ada masalah saat mengambil notifikasi. Ketuk di sini untuk mencoba lagi." -#: src/view/com/posts/Feed.tsx:263 +#: src/view/com/posts/Feed.tsx:265 msgid "There was an issue fetching posts. Tap here to try again." msgstr "Ada masalah saat mengambil postingan. Ketuk di sini untuk mencoba lagi." @@ -4286,7 +4355,7 @@ msgstr "Ini penting jika Anda butuh untuk mengganti email atau reset kata sandi msgid "This link is taking you to the following website:" msgstr "Tautan ini akan membawa Anda ke website:" -#: src/view/screens/ProfileList.tsx:834 +#: src/view/screens/ProfileList.tsx:839 msgid "This list is empty!" msgstr "Daftar ini kosong!" @@ -4318,11 +4387,11 @@ msgstr "" msgid "This warning is only available for posts with media attached." msgstr "Peringatan ini hanya tersedia untuk postingan dengan lampiran media." -#: src/components/dialogs/MutedWords.tsx:236 +#: src/components/dialogs/MutedWords.tsx:285 msgid "This will delete {0} from your muted words. You can always add it back later." msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:237 +#: src/view/com/util/forms/PostDropdownBtn.tsx:282 msgid "This will hide this post from your feeds." msgstr "Ini akan menyembunyikan postingan ini dari feed Anda." @@ -4335,11 +4404,11 @@ msgstr "Preferensi Utasan" msgid "Threaded Mode" msgstr "Mode Utasan" -#: src/Navigation.tsx:255 +#: src/Navigation.tsx:257 msgid "Threads Preferences" msgstr "Preferensi Utas" -#: src/components/dialogs/MutedWords.tsx:95 +#: src/components/dialogs/MutedWords.tsx:113 msgid "Toggle between muted word options." msgstr "" @@ -4353,7 +4422,8 @@ msgstr "Transformasi" #: src/view/com/post-thread/PostThreadItem.tsx:685 #: src/view/com/post-thread/PostThreadItem.tsx:687 -#: src/view/com/util/forms/PostDropdownBtn.tsx:156 +#: src/view/com/util/forms/PostDropdownBtn.tsx:215 +#: src/view/com/util/forms/PostDropdownBtn.tsx:217 msgid "Translate" msgstr "Terjemahkan" @@ -4417,16 +4487,15 @@ msgid "Unfortunately, you do not meet the requirements to create an account." msgstr "Sayangnya, Anda tidak memenuhi syarat untuk membuat akun." #: src/view/com/util/post-ctrls/PostCtrls.tsx:182 -#: src/view/com/util/post-ctrls/PostCtrls.tsx:216 msgid "Unlike" msgstr "Tidak suka" -#: src/components/TagMenu/index.tsx:253 +#: src/components/TagMenu/index.tsx:249 #: src/view/screens/ProfileList.tsx:597 msgid "Unmute" msgstr "Bunyikan" -#: src/components/TagMenu/index.web.tsx:90 +#: src/components/TagMenu/index.web.tsx:104 msgid "Unmute {truncatedTag}" msgstr "" @@ -4434,11 +4503,16 @@ msgstr "" msgid "Unmute Account" msgstr "Bunyikan Akun" -#: src/components/TagMenu/index.tsx:210 -msgid "Unmute all {tag} posts" +#: src/components/TagMenu/index.tsx:208 +msgid "Unmute all {displayTag} posts" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:202 +#: src/components/TagMenu/index.tsx:210 +#~ msgid "Unmute all {tag} posts" +#~ msgstr "" + +#: src/view/com/util/forms/PostDropdownBtn.tsx:251 +#: src/view/com/util/forms/PostDropdownBtn.tsx:256 msgid "Unmute thread" msgstr "Bunyikan utasan" @@ -4522,13 +4596,13 @@ msgstr "Handle pengguna" msgid "User list by {0}" msgstr "Daftar pengguna oleh {0}" -#: src/view/screens/ProfileList.tsx:762 +#: src/view/screens/ProfileList.tsx:763 msgid "User list by <0/>" msgstr "Daftar pengguna oleh<0/>" #: src/view/com/lists/ListCard.tsx:83 #: src/view/com/modals/UserAddRemoveLists.tsx:196 -#: src/view/screens/ProfileList.tsx:760 +#: src/view/screens/ProfileList.tsx:761 msgid "User list by you" msgstr "Daftar pengguna oleh Anda" @@ -4549,7 +4623,7 @@ msgstr "Daftar Pengguna" msgid "Username or email address" msgstr "Nama pengguna atau alamat email" -#: src/view/screens/ProfileList.tsx:796 +#: src/view/screens/ProfileList.tsx:797 msgid "Users" msgstr "Pengguna" @@ -4623,6 +4697,10 @@ msgstr "Peringatkan" msgid "We also think you'll like \"For You\" by Skygaze:" msgstr "" +#: src/screens/Hashtag.tsx:132 +msgid "We couldn't find any results for that hashtag." +msgstr "" + #: src/screens/Deactivated.tsx:133 msgid "We estimate {estimatedTime} until your account is ready." msgstr "" @@ -4643,7 +4721,7 @@ msgstr "" #~ msgid "We recommend \"For You\" by Skygaze:" #~ msgstr "" -#: src/components/dialogs/MutedWords.tsx:161 +#: src/components/dialogs/MutedWords.tsx:204 msgid "We recommend avoiding common words that appear in many posts, since it can result in no posts being shown." msgstr "" @@ -4675,7 +4753,7 @@ msgstr "Kami sangat senang Anda bergabung dengan kami!" msgid "We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @{handleOrDid}." msgstr "Mohon maaf, kami tidak dapat menyelesaikan daftar ini. Jika hal ini terus berlanjut, silakan hubungi pembuat daftar, @{handleOrDid}." -#: src/components/dialogs/MutedWords.tsx:182 +#: src/components/dialogs/MutedWords.tsx:230 msgid "We're sorry, but we weren't able to load your muted words at this time. Please try again." msgstr "" @@ -4683,6 +4761,7 @@ msgstr "" msgid "We're sorry, but your search could not be completed. Please try again in a few minutes." msgstr "Maaf, pencarian Anda tidak dapat dilakukan. Mohon coba lagi dalam beberapa menit." +#: src/components/Lists.tsx:211 #: src/view/screens/NotFound.tsx:48 msgid "We're sorry! We can't find the page you were looking for." msgstr "Maaf! Kami tidak dapat menemukan halaman yang Anda cari." @@ -4837,7 +4916,7 @@ msgstr "Anda belum membuat kata sandi aplikasi. Anda dapat membuatnya dengan men msgid "You have not muted any accounts yet. To mute an account, go to their profile and selected \"Mute account\" from the menu on their account." msgstr "Anda belum membisukan akun lain. Untuk membisukan akun, kunjungi profil mereka dan pilih \"Bisukan akun\" pada menu di akun mereka." -#: src/components/dialogs/MutedWords.tsx:202 +#: src/components/dialogs/MutedWords.tsx:250 msgid "You haven't muted any words or tags yet" msgstr "" @@ -4849,11 +4928,11 @@ msgstr "Anda harus berusia 18 tahun atau lebih untuk mengaktifkan konten dewasa. msgid "You must be 18 years or older to enable adult content" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:129 +#: src/view/com/util/forms/PostDropdownBtn.tsx:147 msgid "You will no longer receive notifications for this thread" msgstr "Anda tidak akan lagi menerima notifikasi untuk utas ini" -#: src/view/com/util/forms/PostDropdownBtn.tsx:132 +#: src/view/com/util/forms/PostDropdownBtn.tsx:150 msgid "You will now receive notifications for this thread" msgstr "Anda sekarang akan menerima notifikasi untuk utas ini" @@ -4879,7 +4958,7 @@ msgstr "" msgid "You've reached the end of your feed! Find some more accounts to follow." msgstr "Anda telah mencapai akhir feed Anda! Temukan beberapa akun lain untuk diikuti." -#: src/view/com/auth/create/Step1.tsx:74 +#: src/view/com/auth/create/Step1.tsx:67 msgid "Your account" msgstr "Akun Anda" @@ -4891,7 +4970,7 @@ msgstr "Akun Anda telah dihapus" msgid "Your account repository, containing all public data records, can be downloaded as a \"CAR\" file. This file does not include media embeds, such as images, or your private data, which must be fetched separately." msgstr "" -#: src/view/com/auth/create/Step1.tsx:238 +#: src/view/com/auth/create/Step1.tsx:215 msgid "Your birth date" msgstr "Tanggal lahir Anda" @@ -4910,8 +4989,8 @@ msgid "Your email appears to be invalid." msgstr "Email Anda tidak valid." #: src/view/com/modals/Waitlist.tsx:109 -msgid "Your email has been saved! We'll be in touch soon." -msgstr "Email Anda telah disimpan. Kami akan segera menghubungi Anda." +#~ msgid "Your email has been saved! We'll be in touch soon." +#~ msgstr "Email Anda telah disimpan. Kami akan segera menghubungi Anda." #: src/view/com/modals/ChangeEmail.tsx:125 msgid "Your email has been updated but not verified. As a next step, please verify your new email." @@ -4943,7 +5022,7 @@ msgstr "Handle lengkap Anda akan menjadi <0>@{0}</0>" #~ msgid "Your invite codes are hidden when logged in using an App Password" #~ msgstr "Kode undangan Anda disembunyikan saat masuk menggunakan Kata Sandi Aplikasi" -#: src/components/dialogs/MutedWords.tsx:173 +#: src/components/dialogs/MutedWords.tsx:221 msgid "Your muted words" msgstr "" diff --git a/src/locale/locales/it/messages.po b/src/locale/locales/it/messages.po index ac09dc107..89f7b7106 100644 --- a/src/locale/locales/it/messages.po +++ b/src/locale/locales/it/messages.po @@ -1,11 +1,11 @@ msgid "" msgstr "" -"Project-Id-Version: \n" +"Project-Id-Version: Italian localization\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2024-01-05 11:44+0530\n" -"PO-Revision-Date: \n" +"PO-Revision-Date: 2024-02-18\n" "Last-Translator: Gabriella Nonino <sandswimmer@gmail.com>\n" -"Language-Team: \n" +"Language-Team: Gabriella Nonino sandswimmer@gmail.com\n" "Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" @@ -32,21 +32,6 @@ msgstr "(no email)" msgid "{following} following" msgstr "{following} seguendo" -#: src/view/shell/desktop/RightNav.tsx:151 -#~ msgid "{invitesAvailable, plural, one {Invite codes: # available} other {Invite codes: # available}}" -#~ msgstr "{invitesAvailable, plural, one {Codici d'invito: # available} other {Codici d'invito: # available}}" - -#: src/view/screens/Settings.tsx:NaN -#~ msgid "{invitesAvailable} invite code available" -#~ msgstr "{invitesAvailable} codice d'invito disponibile" - -#: src/view/screens/Settings.tsx:NaN -#~ msgid "{invitesAvailable} invite codes available" -#~ msgstr "{invitesAvailable} codici d'invito disponibili" - -#~ msgid "{message}" -#~ msgstr "{message}" - #: src/view/shell/Drawer.tsx:440 msgid "{numUnreadNotifications} unread" msgstr "{numUnreadNotifications} non letto" @@ -83,12 +68,12 @@ msgstr "A questo post è stato applicato un avviso di contenuto {0}." msgid "A new version of the app is available. Please update to continue using the app." msgstr "È disponibile una nuova versione dell'app. Aggiorna per continuare a utilizzarla." -#: src/view/com/util/ViewHeader.tsx:83 +#: src/view/com/util/ViewHeader.tsx:89 #: src/view/screens/Search/Search.tsx:647 msgid "Access navigation links and settings" msgstr "Accedi alle impostazioni di navigazione" -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:51 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:52 msgid "Access profile and other navigation links" msgstr "Accedi al profilo e altre impostazioni di navigazione" @@ -135,11 +120,11 @@ msgstr "Account sbloccato" msgid "Account unmuted" msgstr "Account non silenziato" -#: src/components/dialogs/MutedWords.tsx:147 +#: src/components/dialogs/MutedWords.tsx:165 #: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:150 #: src/view/com/modals/ListAddRemoveUsers.tsx:264 #: src/view/com/modals/UserAddRemoveLists.tsx:219 -#: src/view/screens/ProfileList.tsx:812 +#: src/view/screens/ProfileList.tsx:813 msgid "Add" msgstr "Aggiungi" @@ -147,7 +132,7 @@ msgstr "Aggiungi" msgid "Add a content warning" msgstr "Aggiungi un avviso sul contenuto" -#: src/view/screens/ProfileList.tsx:802 +#: src/view/screens/ProfileList.tsx:803 msgid "Add a user to this list" msgstr "Aggiungi un utente a questo elenco" @@ -162,8 +147,7 @@ msgstr "Aggiungi account" msgid "Add alt text" msgstr "Aggiungi testo alternativo" -#: src/view/screens/AppPasswords.tsx:102 -#: src/view/screens/AppPasswords.tsx:143 +#: src/view/screens/AppPasswords.tsx:102 src/view/screens/AppPasswords.tsx:143 #: src/view/screens/AppPasswords.tsx:156 msgid "Add App Password" msgstr "Aggiungi la Password per l'App" @@ -185,11 +169,11 @@ msgstr "Aggiungi la scheda collegata al link" msgid "Add link card:" msgstr "Aggiungi la scheda relazionata al link:" -#: src/components/dialogs/MutedWords.tsx:140 +#: src/components/dialogs/MutedWords.tsx:158 msgid "Add mute word for configured settings" msgstr "" -#: src/components/dialogs/MutedWords.tsx:74 +#: src/components/dialogs/MutedWords.tsx:87 msgid "Add muted words and tags" msgstr "" @@ -237,12 +221,12 @@ msgstr "Avanzato" #: src/view/screens/Feeds.tsx:666 msgid "All the feeds you've saved, right in one place." -msgstr "" +msgstr "Tutti i feed che hai salvato, in un unico posto." #: src/view/com/auth/login/ForgotPasswordForm.tsx:221 #: src/view/com/modals/ChangePassword.tsx:168 msgid "Already have a code?" -msgstr "" +msgstr "Hai già un codice?" #: src/view/com/auth/login/ChooseAccountForm.tsx:98 msgid "Already signed in as @{0}" @@ -273,14 +257,14 @@ msgstr "Una email è stata inviata al tuo indirizzo precedente, {0}. Include un msgid "An issue occurred, please try again." msgstr "Si è verificato un problema, riprova un'altra volta." -#: src/view/com/notifications/FeedItem.tsx:236 +#: src/view/com/notifications/FeedItem.tsx:237 #: src/view/com/threadgate/WhoCanReply.tsx:178 msgid "and" msgstr "e" #: src/screens/Onboarding/index.tsx:32 msgid "Animals" -msgstr "" +msgstr "Animali" #: src/view/screens/LanguageSettings.tsx:95 msgid "App Language" @@ -306,13 +290,14 @@ msgstr "Impostazioni della password dell'app" #~ msgid "App passwords" #~ msgstr "Passwords dell'app" -#: src/Navigation.tsx:237 +#: src/Navigation.tsx:239 #: src/view/screens/AppPasswords.tsx:187 #: src/view/screens/Settings/index.tsx:684 msgid "App Passwords" msgstr "Passwords dell'App" -#: src/view/com/util/forms/PostDropdownBtn.tsx:295 +#: src/view/com/util/forms/PostDropdownBtn.tsx:337 +#: src/view/com/util/forms/PostDropdownBtn.tsx:346 msgid "Appeal content warning" msgstr "Ricorso contro l'avviso sui contenuti" @@ -320,9 +305,6 @@ msgstr "Ricorso contro l'avviso sui contenuti" msgid "Appeal Content Warning" msgstr "Ricorso contro l'Avviso sui Contenuti" -#~ msgid "Appeal Decision" -#~ msgstr "Decisión de apelación" - #: src/view/com/util/moderation/LabelInfo.tsx:52 msgid "Appeal this decision" msgstr "Appella contro questa decisione" @@ -343,12 +325,12 @@ msgstr "Conferma di voler eliminare la password dell'app \"{name}\"?" msgid "Are you sure you'd like to discard this draft?" msgstr "Conferma di voler eliminare questa bozza?" -#: src/components/dialogs/MutedWords.tsx:233 +#: src/components/dialogs/MutedWords.tsx:282 #: src/view/screens/ProfileList.tsx:365 msgid "Are you sure?" msgstr "Confermi?" -#: src/view/com/util/forms/PostDropdownBtn.tsx:278 +#: src/view/com/util/forms/PostDropdownBtn.tsx:322 msgid "Are you sure? This cannot be undone." msgstr "Vuoi proseguire? Questa operazione non può essere annullata." @@ -358,7 +340,7 @@ msgstr "Stai scrivendo in <0>{0}</0>?" #: src/screens/Onboarding/index.tsx:26 msgid "Art" -msgstr "" +msgstr "Arte" #: src/view/com/modals/SelfLabel.tsx:123 msgid "Artistic or non-erotic nudity." @@ -374,7 +356,7 @@ msgstr "Nudità artistica o non erotica." #: src/view/com/post-thread/PostThread.tsx:522 #: src/view/com/post-thread/PostThread.tsx:530 #: src/view/com/profile/ProfileHeader.tsx:649 -#: src/view/com/util/ViewHeader.tsx:81 +#: src/view/com/util/ViewHeader.tsx:87 msgid "Back" msgstr "Indietro" @@ -385,13 +367,13 @@ msgstr "Indietro" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:136 msgid "Based on your interest in {interestsText}" -msgstr "" +msgstr "Basato su i tuoi interessi {interestsText}" #: src/view/screens/Settings/index.tsx:523 msgid "Basics" -msgstr "Nozioni di base" +msgstr "Preferenze" -#: src/view/com/auth/create/Step1.tsx:250 +#: src/view/com/auth/create/Step1.tsx:227 #: src/view/com/modals/BirthDateSettings.tsx:73 msgid "Birthday" msgstr "Compleanno" @@ -430,7 +412,7 @@ msgstr "Bloccato" msgid "Blocked accounts" msgstr "Accounts bloccati" -#: src/Navigation.tsx:130 +#: src/Navigation.tsx:132 #: src/view/screens/ModerationBlockedAccounts.tsx:107 msgid "Blocked Accounts" msgstr "Accounts bloccati" @@ -464,7 +446,7 @@ msgstr "Bluesky" #: src/view/com/auth/server-input/index.tsx:150 msgid "Bluesky is an open network where you can choose your hosting provider. Custom hosting is now available in beta for developers." -msgstr "" +msgstr "Bluesky è una network aperto in cui puoi scegliere il tuo provider di hosting. L'hosting personalizzato adesso è disponibile in versione beta per i developers." #: src/view/com/auth/onboarding/WelcomeDesktop.tsx:80 #: src/view/com/auth/onboarding/WelcomeMobile.tsx:80 @@ -482,20 +464,16 @@ msgid "Bluesky is public." msgstr "Bluesky è pubblico." #: src/view/com/modals/Waitlist.tsx:70 -msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon." -msgstr "Bluesky utilizza gli inviti per costruire una comunità più sana. Se non conosci nessuno con un invito, puoi iscriverti alla lista d'attesa e te ne invieremo uno al più presto." +#~ msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon." +#~ msgstr "Bluesky utilizza gli inviti per costruire una comunità più sana. Se non conosci nessuno con un invito, puoi iscriverti alla lista d'attesa e te ne invieremo uno al più presto." #: src/view/screens/Moderation.tsx:245 msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private." msgstr "Bluesky non mostrerà il tuo profilo e i tuoi post agli utenti disconnessi. Altre app potrebbero non rispettare questa richiesta. Questo non rende il tuo account privato." -#: src/view/com/modals/ServerInput.tsx:78 -#~ msgid "Bluesky.Social" -#~ msgstr "Bluesky.Social" - #: src/screens/Onboarding/index.tsx:33 msgid "Books" -msgstr "" +msgstr "Libri" #: src/view/screens/Settings/index.tsx:859 msgid "Build version {0} {1}" @@ -506,10 +484,6 @@ msgstr "Versione {0} {1}" msgid "Business" msgstr "Attività commerciale" -#: src/view/com/modals/ServerInput.tsx:115 -#~ msgid "Button disabled. Input custom domain to proceed." -#~ msgstr "Pulsante disabilitato. Inserisci il dominio personalizzato per procedere." - #: src/view/com/profile/ProfileSubpageHeader.tsx:157 msgid "by —" msgstr "da—" @@ -527,8 +501,7 @@ msgid "by you" msgstr "da te" #: src/view/com/composer/photos/OpenCameraBtn.tsx:60 -#: src/view/com/util/UserAvatar.tsx:224 -#: src/view/com/util/UserBanner.tsx:40 +#: src/view/com/util/UserAvatar.tsx:224 src/view/com/util/UserBanner.tsx:40 msgid "Camera" msgstr "Fotocamera" @@ -536,7 +509,7 @@ msgstr "Fotocamera" msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must be at least 4 characters long, but no more than 32 characters long." msgstr "Può contenere solo lettere, numeri, spazi, trattini e trattini bassi. Deve contenere almeno 4 caratteri, ma non più di 32 caratteri." -#: src/components/Prompt.tsx:91 +#: src/components/Prompt.tsx:101 #: src/view/com/composer/Composer.tsx:307 #: src/view/com/composer/Composer.tsx:312 #: src/view/com/modals/ChangeEmail.tsx:218 @@ -547,18 +520,15 @@ msgstr "Può contenere solo lettere, numeri, spazi, trattini e trattini bassi. D #: src/view/com/modals/EditImage.tsx:323 #: src/view/com/modals/EditProfile.tsx:249 #: src/view/com/modals/InAppBrowserConsent.tsx:78 -#: src/view/com/modals/LinkWarning.tsx:87 -#: src/view/com/modals/Repost.tsx:87 +#: src/view/com/modals/LinkWarning.tsx:87 src/view/com/modals/Repost.tsx:87 #: src/view/com/modals/VerifyEmail.tsx:247 #: src/view/com/modals/VerifyEmail.tsx:253 -#: src/view/com/modals/Waitlist.tsx:142 #: src/view/screens/Search/Search.tsx:716 #: src/view/shell/desktop/Search.tsx:238 msgid "Cancel" msgstr "Cancella" -#: src/view/com/modals/Confirm.tsx:88 -#: src/view/com/modals/Confirm.tsx:91 +#: src/view/com/modals/Confirm.tsx:88 src/view/com/modals/Confirm.tsx:91 #: src/view/com/modals/CreateOrEditList.tsx:360 #: src/view/com/modals/DeleteAccount.tsx:156 #: src/view/com/modals/DeleteAccount.tsx:234 @@ -571,9 +541,6 @@ msgstr "Cancella" msgid "Cancel account deletion" msgstr "Annulla la cancellazione dell'account" -#~ msgid "Cancel add image alt text" -#~ msgstr "Cancel·la afegir text a la imatge" - #: src/view/com/modals/ChangeHandle.tsx:149 msgid "Cancel change handle" msgstr "Annulla il cambio del tuo nome utente" @@ -596,17 +563,14 @@ msgid "Cancel search" msgstr "Annulla la ricerca" #: src/view/com/modals/Waitlist.tsx:136 -msgid "Cancel waitlist signup" -msgstr "Annulla l'iscrizione alla lista d'attesa" +#~ msgid "Cancel waitlist signup" +#~ msgstr "Annulla l'iscrizione alla lista d'attesa" #: src/view/screens/Settings/index.tsx:334 msgctxt "action" msgid "Change" msgstr "Cambia" -#~ msgid "Change" -#~ msgstr "Canvia" - #: src/view/screens/Settings/index.tsx:696 msgid "Change handle" msgstr "Cambia il nome utente" @@ -622,11 +586,11 @@ msgstr "Cambia la mia email" #: src/view/screens/Settings/index.tsx:732 msgid "Change password" -msgstr "" +msgstr "Cambia la password" #: src/view/screens/Settings/index.tsx:741 msgid "Change Password" -msgstr "" +msgstr "Cambia la Password" #: src/view/com/composer/select-language/SuggestedLanguage.tsx:73 msgid "Change post language to {0}" @@ -634,16 +598,15 @@ msgstr "Cambia la lingua del post a {0}" #: src/view/screens/Settings/index.tsx:733 msgid "Change your Bluesky password" -msgstr "" +msgstr "Cambia la tua password di Bluesky" #: src/view/com/modals/ChangeEmail.tsx:109 msgid "Change Your Email" msgstr "Cambia la tua email" -#: src/screens/Deactivated.tsx:72 -#: src/screens/Deactivated.tsx:76 +#: src/screens/Deactivated.tsx:72 src/screens/Deactivated.tsx:76 msgid "Check my status" -msgstr "" +msgstr "Verifica il mio stato" #: src/view/com/auth/onboarding/RecommendedFeeds.tsx:121 msgid "Check out some recommended feeds. Tap + to add them to your list of pinned feeds." @@ -671,7 +634,7 @@ msgstr "Scegli il servizio" #: src/screens/Onboarding/StepFinished.tsx:135 msgid "Choose the algorithms that power your custom feeds." -msgstr "" +msgstr "Scegli gli algoritmi che compilano i tuoi feed personalizzati." #: src/view/com/auth/onboarding/WelcomeDesktop.tsx:83 #: src/view/com/auth/onboarding/WelcomeMobile.tsx:83 @@ -680,9 +643,9 @@ msgstr "Scegli gli algoritmi che alimentano la tua esperienza con feed personali #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:103 msgid "Choose your main feeds" -msgstr "" +msgstr "Scegli i tuoi feed principali" -#: src/view/com/auth/create/Step1.tsx:219 +#: src/view/com/auth/create/Step1.tsx:196 msgid "Choose your password" msgstr "Scegli la tua password" @@ -713,22 +676,25 @@ msgstr "Annulla la ricerca" msgid "click here" msgstr "clicca qui" -#: src/components/RichText.tsx:189 -#: src/components/TagMenu/index.web.tsx:125 +#: src/components/TagMenu/index.web.tsx:138 msgid "Click here to open tag menu for {tag}" msgstr "" +#: src/components/RichText.tsx:191 +msgid "Click here to open tag menu for #{tag}" +msgstr "" + #: src/screens/Onboarding/index.tsx:35 msgid "Climate" -msgstr "" +msgstr "Clima" #: src/view/com/modals/ChangePassword.tsx:265 #: src/view/com/modals/ChangePassword.tsx:268 msgid "Close" -msgstr "" +msgstr "Chiudi" -#: src/components/Dialog/index.web.tsx:80 -#: src/components/Dialog/index.web.tsx:194 +#: src/components/Dialog/index.web.tsx:84 +#: src/components/Dialog/index.web.tsx:198 msgid "Close active dialog" msgstr "Chiudi il dialogo attivo" @@ -752,7 +718,7 @@ msgstr "Chiudi il visualizzatore di immagini" msgid "Close navigation footer" msgstr "Chiudi la navigazione del footer" -#: src/components/TagMenu/index.tsx:266 +#: src/components/TagMenu/index.tsx:262 msgid "Close this dialog" msgstr "" @@ -772,26 +738,26 @@ msgstr "Chiude l'editore del post ed elimina la bozza del post" msgid "Closes viewer for header image" msgstr "Chiude il visualizzatore dell'immagine di intestazione" -#: src/view/com/notifications/FeedItem.tsx:317 +#: src/view/com/notifications/FeedItem.tsx:318 msgid "Collapses list of users for a given notification" msgstr "Comprime l'elenco degli utenti per una determinata notifica" #: src/screens/Onboarding/index.tsx:41 msgid "Comedy" -msgstr "" +msgstr "Commedia" #: src/screens/Onboarding/index.tsx:27 msgid "Comics" -msgstr "" +msgstr "Fumetti" -#: src/Navigation.tsx:227 +#: src/Navigation.tsx:229 #: src/view/screens/CommunityGuidelines.tsx:32 msgid "Community Guidelines" msgstr "Linee guida della community" #: src/screens/Onboarding/StepFinished.tsx:148 msgid "Complete onboarding and start using your account" -msgstr "" +msgstr "Completa l'incorporazione e inizia a utilizzare il tuo account" #: src/view/com/auth/create/Step3.tsx:73 msgid "Complete the challenge" @@ -807,9 +773,9 @@ msgstr "Scrivi la risposta" #: src/screens/Onboarding/StepModeration/ModerationOption.tsx:67 msgid "Configure content filtering setting for category: {0}" -msgstr "" +msgstr "Configura l'impostazione del filtro dei contenuti per la categoria:{0}" -#: src/components/Prompt.tsx:113 +#: src/components/Prompt.tsx:124 #: src/view/com/modals/AppealLabel.tsx:98 #: src/view/com/modals/SelfLabel.tsx:154 #: src/view/com/modals/VerifyEmail.tsx:231 @@ -819,8 +785,7 @@ msgstr "" msgid "Confirm" msgstr "Conferma" -#: src/view/com/modals/Confirm.tsx:75 -#: src/view/com/modals/Confirm.tsx:78 +#: src/view/com/modals/Confirm.tsx:75 src/view/com/modals/Confirm.tsx:78 msgctxt "action" msgid "Confirm" msgstr "Conferma" @@ -849,8 +814,8 @@ msgid "Confirmation code" msgstr "Codice di conferma" #: src/view/com/modals/Waitlist.tsx:120 -msgid "Confirms signing up {email} to the waitlist" -msgstr "Conferma l'iscrizione di {email} alla lista d'attesa" +#~ msgid "Confirms signing up {email} to the waitlist" +#~ msgstr "Conferma l'iscrizione di {email} alla lista d'attesa" #: src/view/com/auth/create/CreateAccount.tsx:193 #: src/view/com/auth/login/LoginForm.tsx:278 @@ -902,19 +867,19 @@ msgstr "Continua" #: src/screens/Onboarding/StepModeration/index.tsx:115 #: src/screens/Onboarding/StepTopicalFeeds.tsx:111 msgid "Continue to next step" -msgstr "" +msgstr "Vai al passaggio successivo" #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:167 msgid "Continue to the next step" -msgstr "" +msgstr "Vai al passaggio successivo" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:191 msgid "Continue to the next step without following any accounts" -msgstr "" +msgstr "Vai al passaggio successivo senza seguire nessun account" #: src/screens/Onboarding/index.tsx:44 msgid "Cooking" -msgstr "" +msgstr "Cucina" #: src/view/com/modals/AddAppPasswords.tsx:195 #: src/view/com/modals/InviteCodes.tsx:182 @@ -927,7 +892,7 @@ msgstr "Versione di build copiata nella clipboard" #: src/view/com/modals/AddAppPasswords.tsx:76 #: src/view/com/modals/InviteCodes.tsx:152 -#: src/view/com/util/forms/PostDropdownBtn.tsx:143 +#: src/view/com/util/forms/PostDropdownBtn.tsx:161 msgid "Copied to clipboard" msgstr "Copiato nel clipboard" @@ -943,7 +908,8 @@ msgstr "Copia" msgid "Copy link to list" msgstr "Copia il link alla lista" -#: src/view/com/util/forms/PostDropdownBtn.tsx:184 +#: src/view/com/util/forms/PostDropdownBtn.tsx:231 +#: src/view/com/util/forms/PostDropdownBtn.tsx:237 msgid "Copy link to post" msgstr "Copia il link al post" @@ -951,11 +917,12 @@ msgstr "Copia il link al post" msgid "Copy link to profile" msgstr "Copia il link al profilo" -#: src/view/com/util/forms/PostDropdownBtn.tsx:170 +#: src/view/com/util/forms/PostDropdownBtn.tsx:223 +#: src/view/com/util/forms/PostDropdownBtn.tsx:225 msgid "Copy post text" msgstr "Copia il testo del post" -#: src/Navigation.tsx:232 +#: src/Navigation.tsx:234 #: src/view/screens/CopyrightPolicy.tsx:29 msgid "Copyright Policy" msgstr "Politica sul diritto d'autore" @@ -964,7 +931,7 @@ msgstr "Politica sul diritto d'autore" msgid "Could not load feed" msgstr "Feed non caricato" -#: src/view/screens/ProfileList.tsx:888 +#: src/view/screens/ProfileList.tsx:893 msgid "Could not load list" msgstr "No si è potuto caricare la lista" @@ -1013,12 +980,12 @@ msgstr "Crea una scheda con una miniatura. La scheda si collega a {url}" #: src/screens/Onboarding/index.tsx:29 msgid "Culture" -msgstr "" +msgstr "Cultura" #: src/view/com/auth/server-input/index.tsx:95 #: src/view/com/auth/server-input/index.tsx:96 msgid "Custom" -msgstr "" +msgstr "Personalizzato" #: src/view/com/modals/ChangeHandle.tsx:389 msgid "Custom domain" @@ -1027,16 +994,12 @@ msgstr "Dominio personalizzato" #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:106 #: src/view/screens/Feeds.tsx:692 msgid "Custom feeds built by the community bring you new experiences and help you find the content you love." -msgstr "" +msgstr "I feed personalizzati creati dalla comunità ti offrono nuove esperienze e ti aiutano a trovare i contenuti che ami." #: src/view/screens/PreferencesExternalEmbeds.tsx:55 msgid "Customize media from external sites." msgstr "Personalizza i media da i siti esterni." -#: src/view/screens/Settings.tsx:687 -#~ msgid "Danger Zone" -#~ msgstr "Zona di Pericolo" - #: src/view/screens/Settings/index.tsx:485 #: src/view/screens/Settings/index.tsx:511 msgid "Dark" @@ -1048,7 +1011,7 @@ msgstr "Aspetto scuro" #: src/view/screens/Settings/index.tsx:498 msgid "Dark Theme" -msgstr "" +msgstr "Tema scuro" #: src/view/screens/Debug.tsx:83 msgid "Debug panel" @@ -1062,8 +1025,7 @@ msgstr "Eliminare l'account" msgid "Delete Account" msgstr "Eliminare l'Account" -#: src/view/screens/AppPasswords.tsx:222 -#: src/view/screens/AppPasswords.tsx:242 +#: src/view/screens/AppPasswords.tsx:222 src/view/screens/AppPasswords.tsx:242 msgid "Delete app password" msgstr "Elimina la password dell'app" @@ -1074,23 +1036,20 @@ msgstr "Elimina la lista" #: src/view/com/modals/DeleteAccount.tsx:223 msgid "Delete my account" -msgstr "Cancella il mio account" - -#: src/view/screens/Settings.tsx:706 -#~ msgid "Delete my account…" -#~ msgstr "Cancella il mio account…" +msgstr "Cancellare account" #: src/view/screens/Settings/index.tsx:784 msgid "Delete My Account…" -msgstr "" +msgstr "Cancellare Account…" -#: src/view/com/util/forms/PostDropdownBtn.tsx:273 +#: src/view/com/util/forms/PostDropdownBtn.tsx:317 +#: src/view/com/util/forms/PostDropdownBtn.tsx:326 msgid "Delete post" msgstr "Elimina il post" -#: src/view/com/util/forms/PostDropdownBtn.tsx:277 +#: src/view/com/util/forms/PostDropdownBtn.tsx:321 msgid "Delete this post?" -msgstr "Elimina questo post?" +msgstr "Eliminare questo post?" #: src/view/com/util/post-embeds/QuoteEmbed.tsx:70 msgid "Deleted" @@ -1120,7 +1079,7 @@ msgstr "Volevi dire qualcosa?" #: src/view/screens/Settings/index.tsx:504 msgid "Dim" -msgstr "" +msgstr "Fioco" #: src/view/com/composer/Composer.tsx:151 msgid "Discard" @@ -1137,15 +1096,11 @@ msgstr "Scoraggia le app dal mostrare il mio account agli utenti disconnessi" #: src/view/com/posts/FollowingEmptyState.tsx:74 #: src/view/com/posts/FollowingEndOfFeed.tsx:75 msgid "Discover new custom feeds" -msgstr "Scopri nuovi feed personalizzati" - -#: src/view/screens/Feeds.tsx:409 -#~ msgid "Discover new feeds" -#~ msgstr "Scopri nuovi feeds" +msgstr "Scopri nuovi feeds personalizzati" #: src/view/screens/Feeds.tsx:689 msgid "Discover New Feeds" -msgstr "" +msgstr "Scopri nuovi feeds" #: src/view/com/modals/EditProfile.tsx:192 msgid "Display name" @@ -1160,14 +1115,13 @@ msgid "Domain verified!" msgstr "Dominio verificato!" #: src/view/com/auth/create/Step1.tsx:170 -msgid "Don't have an invite code?" -msgstr "Non hai un codice di invito?" +#~ msgid "Don't have an invite code?" +#~ msgstr "Non hai un codice di invito?" #: src/view/com/auth/onboarding/RecommendedFollows.tsx:86 #: src/view/com/modals/EditImage.tsx:333 #: src/view/com/modals/ListAddRemoveUsers.tsx:144 -#: src/view/com/modals/SelfLabel.tsx:157 -#: src/view/com/modals/Threadgate.tsx:129 +#: src/view/com/modals/SelfLabel.tsx:157 src/view/com/modals/Threadgate.tsx:129 #: src/view/com/modals/Threadgate.tsx:132 #: src/view/com/modals/UserAddRemoveLists.tsx:95 #: src/view/com/modals/UserAddRemoveLists.tsx:98 @@ -1202,20 +1156,20 @@ msgstr "Usa il doppio tocco per accedere" #: src/view/screens/Settings/index.tsx:755 msgid "Download Bluesky account data (repository)" -msgstr "" +msgstr "Scarica i dati dell'account Bluesky (archivio)" #: src/view/screens/Settings/ExportCarDialog.tsx:59 #: src/view/screens/Settings/ExportCarDialog.tsx:63 msgid "Download CAR file" -msgstr "" +msgstr "Scarica il CAR file" #: src/view/com/composer/text-input/TextInput.web.tsx:249 msgid "Drop to add images" -msgstr "" +msgstr "Trascina e rilascia per aggiungere immagini" #: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:111 msgid "Due to Apple policies, adult content can only be enabled on the web after completing sign up." -msgstr "" +msgstr "A causa delle politiche di Apple, i contenuti per adulti possono essere abilitati sul Web solo dopo aver completato la registrazione." #: src/view/com/modals/EditProfile.tsx:185 msgid "e.g. Alice Roberts" @@ -1263,7 +1217,7 @@ msgstr "Modifica i dettagli della lista" msgid "Edit Moderation List" msgstr "Modifica l'elenco di moderazione" -#: src/Navigation.tsx:242 +#: src/Navigation.tsx:244 #: src/view/screens/Feeds.tsx:434 #: src/view/screens/SavedFeeds.tsx:84 msgid "Edit My Feeds" @@ -1281,7 +1235,7 @@ msgstr "Modifica il profilo" msgid "Edit Profile" msgstr "Modifica il Profilo" -#: src/view/com/home/HomeHeaderLayout.web.tsx:59 +#: src/view/com/home/HomeHeaderLayout.web.tsx:62 #: src/view/screens/Feeds.tsx:355 msgid "Edit Saved Feeds" msgstr "Modifica i feeds memorizzati" @@ -1300,16 +1254,15 @@ msgstr "Modifica la descrizione del tuo profilo" #: src/screens/Onboarding/index.tsx:34 msgid "Education" -msgstr "" +msgstr "Formazione scolastica" -#: src/view/com/auth/create/Step1.tsx:199 +#: src/view/com/auth/create/Step1.tsx:176 #: src/view/com/auth/login/ForgotPasswordForm.tsx:156 #: src/view/com/modals/ChangeEmail.tsx:141 -#: src/view/com/modals/Waitlist.tsx:88 msgid "Email" msgstr "Email" -#: src/view/com/auth/create/Step1.tsx:190 +#: src/view/com/auth/create/Step1.tsx:167 #: src/view/com/auth/login/ForgotPasswordForm.tsx:147 msgid "Email address" msgstr "Indirizzo email" @@ -1342,7 +1295,7 @@ msgstr "Attiva Contenuto per Adulti" #: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:76 #: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:77 msgid "Enable adult content in your feeds" -msgstr "" +msgstr "Abilita i contenuti per adulti nei tuoi feeds" #: src/view/com/modals/EmbedConsent.tsx:97 msgid "Enable External Media" @@ -1364,8 +1317,8 @@ msgstr "Fine del feed" msgid "Enter a name for this App Password" msgstr "Inserisci un nome per questa password dell'app" -#: src/components/dialogs/MutedWords.tsx:87 -#: src/components/dialogs/MutedWords.tsx:88 +#: src/components/dialogs/MutedWords.tsx:100 +#: src/components/dialogs/MutedWords.tsx:101 msgid "Enter a word or tag" msgstr "" @@ -1373,12 +1326,9 @@ msgstr "" msgid "Enter Confirmation Code" msgstr "Inserire il codice di conferma" -#~ msgid "Enter the address of your provider:" -#~ msgstr "Introdueix l'adreça del teu proveïdor:" - #: src/view/com/modals/ChangePassword.tsx:151 msgid "Enter the code you received to change your password." -msgstr "" +msgstr "Inserisci il codice che hai ricevuto per modificare la tua password." #: src/view/com/modals/ChangeHandle.tsx:371 msgid "Enter the domain you want to use" @@ -1388,16 +1338,16 @@ msgstr "Inserisci il dominio che vuoi utilizzare" msgid "Enter the email you used to create your account. We'll send you a \"reset code\" so you can set a new password." msgstr "Inserisci l'e-mail che hai utilizzato per creare il tuo account. Ti invieremo un \"codice di reset\" in modo che tu possa impostare una nuova password." -#: src/view/com/auth/create/Step1.tsx:251 +#: src/view/com/auth/create/Step1.tsx:228 #: src/view/com/modals/BirthDateSettings.tsx:74 msgid "Enter your birth date" msgstr "Inserisci la tua data di nascita" #: src/view/com/modals/Waitlist.tsx:78 -msgid "Enter your email" -msgstr "Inserisci la tua email" +#~ msgid "Enter your email" +#~ msgstr "Inserisci la tua email" -#: src/view/com/auth/create/Step1.tsx:195 +#: src/view/com/auth/create/Step1.tsx:172 msgid "Enter your email address" msgstr "Inserisci il tuo indirizzo email" @@ -1443,8 +1393,8 @@ msgid "Exits inputting search query" msgstr "Uscita dall'inserzione della domanda di ricerca" #: src/view/com/modals/Waitlist.tsx:138 -msgid "Exits signing up for waitlist with {email}" -msgstr "Uscita dall'iscrizione alla lista d'attesa con {email}" +#~ msgid "Exits signing up for waitlist with {email}" +#~ msgstr "Uscita dall'iscrizione alla lista d'attesa con {email}" #: src/view/com/lightbox/Lightbox.web.tsx:163 msgid "Expand alt text" @@ -1457,12 +1407,12 @@ msgstr "Espandi o comprimi l'intero post a cui stai rispondendo" #: src/view/screens/Settings/index.tsx:753 msgid "Export my data" -msgstr "" +msgstr "Esporta i miei dati" #: src/view/screens/Settings/ExportCarDialog.tsx:44 #: src/view/screens/Settings/index.tsx:764 msgid "Export My Data" -msgstr "" +msgstr "Esporta i miei dati" #: src/view/com/modals/EmbedConsent.tsx:64 msgid "External Media" @@ -1473,7 +1423,7 @@ msgstr "Media esterni" msgid "External media may allow websites to collect information about you and your device. No information is sent or requested until you press the \"play\" button." msgstr "I multimediali esterni possono consentire ai siti web di raccogliere informazioni su di te e sul tuo dispositivo. Nessuna informazione viene inviata o richiesta finché non si preme il pulsante \"Riproduci\"." -#: src/Navigation.tsx:261 +#: src/Navigation.tsx:263 #: src/view/screens/PreferencesExternalEmbeds.tsx:52 #: src/view/screens/Settings/index.tsx:657 msgid "External Media Preferences" @@ -1492,7 +1442,7 @@ msgstr "Impossibile creare la password dell'app." msgid "Failed to create the list. Check your internet connection and try again." msgstr "Impossibile creare l'elenco. Controlla la connessione Internet e riprova." -#: src/view/com/util/forms/PostDropdownBtn.tsx:110 +#: src/view/com/util/forms/PostDropdownBtn.tsx:128 msgid "Failed to delete post, please try again" msgstr "Non possiamo eliminare il post, riprova di nuovo" @@ -1501,13 +1451,13 @@ msgstr "Non possiamo eliminare il post, riprova di nuovo" msgid "Failed to load recommended feeds" msgstr "Non possiamo caricare i feed consigliati" -#: src/Navigation.tsx:192 +#: src/Navigation.tsx:194 msgid "Feed" msgstr "Feed" #: src/view/com/feeds/FeedSourceCard.tsx:231 msgid "Feed by {0}" -msgstr "Feed realizzato da {0}" +msgstr "Feed fatto da {0}" #: src/view/screens/Feeds.tsx:605 msgid "Feed offline" @@ -1522,13 +1472,12 @@ msgstr "Feed offline" msgid "Feedback" msgstr "Commenti" -#: src/Navigation.tsx:445 +#: src/Navigation.tsx:452 #: src/view/screens/Feeds.tsx:419 #: src/view/screens/Feeds.tsx:524 #: src/view/screens/Profile.tsx:184 #: src/view/shell/bottom-bar/BottomBar.tsx:181 -#: src/view/shell/desktop/LeftNav.tsx:342 -#: src/view/shell/Drawer.tsx:476 +#: src/view/shell/desktop/LeftNav.tsx:342 src/view/shell/Drawer.tsx:476 #: src/view/shell/Drawer.tsx:477 msgid "Feeds" msgstr "Feeds" @@ -1543,11 +1492,11 @@ msgstr "I feed sono algoritmi personalizzati che gli utenti creano con un minimo #: src/screens/Onboarding/StepTopicalFeeds.tsx:76 msgid "Feeds can be topical as well!" -msgstr "" +msgstr "I feeds possono anche avere tematiche!" #: src/screens/Onboarding/StepFinished.tsx:151 msgid "Finalizing" -msgstr "" +msgstr "Finalizzando" #: src/view/com/posts/CustomFeedEmptyState.tsx:47 #: src/view/com/posts/FollowingEmptyState.tsx:57 @@ -1581,18 +1530,17 @@ msgstr "Ottimizza i la visualizzazione delle discussioni." #: src/screens/Onboarding/index.tsx:38 msgid "Fitness" -msgstr "" +msgstr "Fitness" #: src/screens/Onboarding/StepFinished.tsx:131 msgid "Flexible" -msgstr "" +msgstr "Flessibile" #: src/view/com/modals/EditImage.tsx:115 msgid "Flip horizontal" msgstr "Gira in orizzontale" -#: src/view/com/modals/EditImage.tsx:120 -#: src/view/com/modals/EditImage.tsx:287 +#: src/view/com/modals/EditImage.tsx:120 src/view/com/modals/EditImage.tsx:287 msgid "Flip vertically" msgstr "Gira in verticale" @@ -1615,11 +1563,11 @@ msgstr "Segui {0}" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:179 msgid "Follow All" -msgstr "" +msgstr "Segui tutti" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:174 msgid "Follow selected accounts and continue to the next step" -msgstr "" +msgstr "Segui gli account selezionati e vai al passaggio successivo" #: src/view/com/auth/onboarding/RecommendedFollows.tsx:64 msgid "Follow some users to get started. We can recommend you more users based on who you find interesting." @@ -1643,24 +1591,21 @@ msgstr "ti segue" #: src/view/screens/ProfileFollowers.tsx:25 msgid "Followers" -msgstr "Seguiti" - -#~ msgid "following" -#~ msgstr "seguint" +msgstr "Followers" #: src/view/com/post-thread/PostThreadFollowBtn.tsx:136 #: src/view/com/profile/ProfileHeader.tsx:495 #: src/view/screens/ProfileFollows.tsx:25 msgid "Following" -msgstr "Seguiti" +msgstr "Following" #: src/view/com/profile/ProfileHeader.tsx:149 msgid "Following {0}" msgstr "Seguiti {0}" -#: src/Navigation.tsx:248 -#: src/view/com/home/HomeHeaderLayout.web.tsx:45 -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:83 +#: src/Navigation.tsx:250 +#: src/view/com/home/HomeHeaderLayout.web.tsx:50 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:84 #: src/view/screens/PreferencesFollowingFeed.tsx:104 #: src/view/screens/Settings/index.tsx:543 msgid "Following Feed Preferences" @@ -1676,7 +1621,7 @@ msgstr "Ti Segue" #: src/screens/Onboarding/index.tsx:43 msgid "Food" -msgstr "" +msgstr "Gastronomia" #: src/view/com/modals/DeleteAccount.tsx:111 msgid "For security reasons, we'll need to send a confirmation code to your email address." @@ -1694,11 +1639,15 @@ msgstr "Dimenticato" msgid "Forgot password" msgstr "Ho dimenticato il password" -#: src/view/com/auth/login/Login.tsx:127 -#: src/view/com/auth/login/Login.tsx:143 +#: src/view/com/auth/login/Login.tsx:127 src/view/com/auth/login/Login.tsx:143 msgid "Forgot Password" msgstr "Ho dimenticato il Password" +#: src/screens/Hashtag.tsx:108 +#: src/screens/Hashtag.tsx:148 +msgid "From @{sanitizedAuthor}" +msgstr "" + #: src/view/com/posts/FeedItem.tsx:189 msgctxt "from-feed" msgid "From <0/>" @@ -1713,8 +1662,7 @@ msgstr "Galleria" msgid "Get Started" msgstr "Inizia" -#: src/view/com/auth/LoggedOut.tsx:81 -#: src/view/com/auth/LoggedOut.tsx:82 +#: src/view/com/auth/LoggedOut.tsx:81 src/view/com/auth/LoggedOut.tsx:82 #: src/view/com/util/moderation/ScreenHider.tsx:123 #: src/view/shell/desktop/LeftNav.tsx:104 msgid "Go back" @@ -1722,15 +1670,14 @@ msgstr "Torna indietro" #: src/view/screens/ProfileFeed.tsx:106 #: src/view/screens/ProfileFeed.tsx:111 -#: src/view/screens/ProfileList.tsx:897 #: src/view/screens/ProfileList.tsx:902 +#: src/view/screens/ProfileList.tsx:907 msgid "Go Back" msgstr "Torna Indietro" -#: src/screens/Onboarding/Layout.tsx:104 -#: src/screens/Onboarding/Layout.tsx:193 +#: src/screens/Onboarding/Layout.tsx:104 src/screens/Onboarding/Layout.tsx:193 msgid "Go back to previous step" -msgstr "" +msgstr "Torna al passaggio precedente" #: src/view/screens/Search/Search.tsx:747 #: src/view/shell/desktop/Search.tsx:262 @@ -1749,8 +1696,16 @@ msgstr "Seguente" msgid "Handle" msgstr "Nome Utente" +#: src/Navigation.tsx:270 +msgid "Hashtag" +msgstr "" + #: src/components/RichText.tsx:188 -msgid "Hashtag: {tag}" +#~ msgid "Hashtag: {tag}" +#~ msgstr "" + +#: src/components/RichText.tsx:190 +msgid "Hashtag: #{tag}" msgstr "" #: src/view/com/auth/create/CreateAccount.tsx:208 @@ -1764,15 +1719,15 @@ msgstr "Aiuto" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:132 msgid "Here are some accounts for you to follow" -msgstr "" +msgstr "Ecco alcuni account da seguire" #: src/screens/Onboarding/StepTopicalFeeds.tsx:85 msgid "Here are some popular topical feeds. You can choose to follow as many as you like." -msgstr "" +msgstr "Ecco alcuni feed più visitati. Puoi seguire quanti ne vuoi." #: src/screens/Onboarding/StepTopicalFeeds.tsx:80 msgid "Here are some topical feeds based on your interests: {interestsText}. You can choose to follow as many as you like." -msgstr "" +msgstr "Ecco alcuni feed di attualità scelti in base ai tuoi interessi: {interestsText}. Puoi seguire quanti ne vuoi." #: src/view/com/modals/AddAppPasswords.tsx:153 msgid "Here is your app password." @@ -1786,12 +1741,13 @@ msgid "Hide" msgstr "Nascondi" #: src/view/com/modals/ContentFilteringSettings.tsx:224 -#: src/view/com/notifications/FeedItem.tsx:325 +#: src/view/com/notifications/FeedItem.tsx:326 msgctxt "action" msgid "Hide" msgstr "Nascondi" -#: src/view/com/util/forms/PostDropdownBtn.tsx:232 +#: src/view/com/util/forms/PostDropdownBtn.tsx:276 +#: src/view/com/util/forms/PostDropdownBtn.tsx:287 msgid "Hide post" msgstr "Nascondi il messaggio" @@ -1800,11 +1756,11 @@ msgstr "Nascondi il messaggio" msgid "Hide the content" msgstr "Nascondere il contenuto" -#: src/view/com/util/forms/PostDropdownBtn.tsx:236 +#: src/view/com/util/forms/PostDropdownBtn.tsx:280 msgid "Hide this post?" msgstr "Vuoi nascondere questo post?" -#: src/view/com/notifications/FeedItem.tsx:315 +#: src/view/com/notifications/FeedItem.tsx:316 msgid "Hide user list" msgstr "Nascondi elenco utenti" @@ -1832,7 +1788,7 @@ msgstr "Il server del feed ha dato una risposta negativa. Informa il proprietari msgid "Hmm, we're having trouble finding this feed. It may have been deleted." msgstr "Stiamo riscontrando problemi nel trovare questo feed. Potrebbe essere stato cancellato." -#: src/Navigation.tsx:435 +#: src/Navigation.tsx:442 #: src/view/shell/bottom-bar/BottomBar.tsx:137 #: src/view/shell/desktop/LeftNav.tsx:306 #: src/view/shell/Drawer.tsx:398 @@ -1840,21 +1796,17 @@ msgstr "Stiamo riscontrando problemi nel trovare questo feed. Potrebbe essere st msgid "Home" msgstr "Home" -#: src/Navigation.tsx:247 -#: src/view/com/pager/FeedsTabBarMobile.tsx:123 +#: src/Navigation.tsx:247 src/view/com/pager/FeedsTabBarMobile.tsx:123 #: src/view/screens/PreferencesHomeFeed.tsx:104 #: src/view/screens/Settings/index.tsx:543 #~ msgid "Home Feed Preferences" #~ msgstr "Preferenze per i feed per la pagina d'inizio" -#: src/view/com/auth/create/Step1.tsx:82 +#: src/view/com/auth/create/Step1.tsx:75 #: src/view/com/auth/login/ForgotPasswordForm.tsx:120 msgid "Hosting provider" msgstr "Servizio di hosting" -#~ msgid "Hosting provider address" -#~ msgstr "Adreça del proveïdor d'allotjament" - #: src/view/com/modals/InAppBrowserConsent.tsx:44 msgid "How should we open this link?" msgstr "Come dovremmo aprire questo link?" @@ -1881,7 +1833,7 @@ msgstr "Se niente è selezionato, adatto a tutte le età ." #: src/view/com/modals/ChangePassword.tsx:146 msgid "If you want to change your password, we will send you a code to verify that this is your account." -msgstr "" +msgstr "Se vuoi modificare la password, ti invieremo un codice per verificare se questo è il tuo account." #: src/view/com/util/images/Gallery.tsx:38 msgid "Image" @@ -1891,8 +1843,7 @@ msgstr "Immagine" msgid "Image alt text" msgstr "Testo alternativo dell'immagine" -#: src/view/com/util/UserAvatar.tsx:311 -#: src/view/com/util/UserBanner.tsx:118 +#: src/view/com/util/UserAvatar.tsx:311 src/view/com/util/UserBanner.tsx:118 msgid "Image options" msgstr "Opzioni per l'immagine" @@ -1904,11 +1855,11 @@ msgstr "Inserisci il codice inviato alla tua email per reimpostare la password" msgid "Input confirmation code for account deletion" msgstr "Inserisci il codice di conferma per la cancellazione dell'account" -#: src/view/com/auth/create/Step1.tsx:200 +#: src/view/com/auth/create/Step1.tsx:177 msgid "Input email for Bluesky account" msgstr "Inserisci l'e-mail per l'account di Bluesky" -#: src/view/com/auth/create/Step1.tsx:158 +#: src/view/com/auth/create/Step1.tsx:151 msgid "Input invite code to proceed" msgstr "Inserisci il codice di invito per procedere" @@ -1941,8 +1892,8 @@ msgstr "Inserisci il nome utente o l'indirizzo email che hai utilizzato al momen #~ msgstr "Inserisci il codice di verifica che ti abbiamo inviato tramite SMS" #: src/view/com/modals/Waitlist.tsx:90 -msgid "Input your email to get on the Bluesky waitlist" -msgstr "Inserisci la tua email per entrare nella lista d'attesa di Bluesky" +#~ msgid "Input your email to get on the Bluesky waitlist" +#~ msgstr "Inserisci la tua email per entrare nella lista d'attesa di Bluesky" #: src/view/com/auth/login/LoginForm.tsx:229 msgid "Input your password" @@ -1960,16 +1911,12 @@ msgstr "Protocollo del post non valido o non supportato" msgid "Invalid username or password" msgstr "Nome dell'utente o password errato" -#: src/view/screens/Settings.tsx:411 -#~ msgid "Invite" -#~ msgstr "Invita" - #: src/view/com/modals/InviteCodes.tsx:93 msgid "Invite a Friend" msgstr "Invita un amico" -#: src/view/com/auth/create/Step1.tsx:148 -#: src/view/com/auth/create/Step1.tsx:157 +#: src/view/com/auth/create/Step1.tsx:141 +#: src/view/com/auth/create/Step1.tsx:150 msgid "Invite code" msgstr "Codice d'invito" @@ -1981,17 +1928,13 @@ msgstr "Codice invito non accettato. Controlla di averlo inserito correttamente msgid "Invite codes: {0} available" msgstr "Codici di invito: {0} disponibili" -#: src/view/shell/Drawer.tsx:645 -#~ msgid "Invite codes: {invitesAvailable} available" -#~ msgstr "Codici di invito: {invitesAvailable} disponibili" - #: src/view/com/modals/InviteCodes.tsx:169 msgid "Invite codes: 1 available" msgstr "Codici di invito: 1 disponibile" #: src/screens/Onboarding/StepFollowingFeed.tsx:64 msgid "It shows posts from the people you follow as they happen." -msgstr "" +msgstr "Mostra i post delle persone che segui." #: src/view/com/auth/HomeLoggedOutCTA.tsx:99 #: src/view/com/auth/SplashScreen.web.tsx:138 @@ -1999,21 +1942,21 @@ msgid "Jobs" msgstr "Lavori" #: src/view/com/modals/Waitlist.tsx:67 -msgid "Join the waitlist" -msgstr "Iscriviti alla lista d'attesa" +#~ msgid "Join the waitlist" +#~ msgstr "Iscriviti alla lista d'attesa" #: src/view/com/auth/create/Step1.tsx:174 #: src/view/com/auth/create/Step1.tsx:178 -msgid "Join the waitlist." -msgstr "Iscriviti alla lista d'attesa." +#~ msgid "Join the waitlist." +#~ msgstr "Iscriviti alla lista d'attesa." #: src/view/com/modals/Waitlist.tsx:128 -msgid "Join Waitlist" -msgstr "Iscriviti alla Lista d'Attesa" +#~ msgid "Join Waitlist" +#~ msgstr "Iscriviti alla Lista d'Attesa" #: src/screens/Onboarding/index.tsx:24 msgid "Journalism" -msgstr "" +msgstr "Giornalismo" #: src/view/com/composer/select-language/SelectLangBtn.tsx:104 msgid "Language selection" @@ -2023,7 +1966,7 @@ msgstr "Seleziona la lingua" msgid "Language settings" msgstr "Impostazione delle lingue" -#: src/Navigation.tsx:140 +#: src/Navigation.tsx:142 #: src/view/screens/LanguageSettings.tsx:89 msgid "Language Settings" msgstr "Impostazione delle Lingue" @@ -2068,23 +2011,21 @@ msgstr "Stai lasciando Bluesky" #: src/screens/Deactivated.tsx:128 msgid "left to go." -msgstr "" +msgstr "mancano." #: src/view/screens/Settings/index.tsx:278 msgid "Legacy storage cleared, you need to restart the app now." msgstr "L'archivio legacy è stato cancellato, riattiva la app." -#: src/view/com/auth/login/Login.tsx:128 -#: src/view/com/auth/login/Login.tsx:144 +#: src/view/com/auth/login/Login.tsx:128 src/view/com/auth/login/Login.tsx:144 msgid "Let's get your password reset!" msgstr "Reimpostazione della password!" #: src/screens/Onboarding/StepFinished.tsx:151 msgid "Let's go!" -msgstr "" +msgstr "Andiamo!" -#: src/view/com/util/UserAvatar.tsx:248 -#: src/view/com/util/UserBanner.tsx:62 +#: src/view/com/util/UserAvatar.tsx:248 src/view/com/util/UserBanner.tsx:62 msgid "Library" msgstr "Biblioteca" @@ -2093,7 +2034,6 @@ msgid "Light" msgstr "Chiaro" #: src/view/com/util/post-ctrls/PostCtrls.tsx:182 -#: src/view/com/util/post-ctrls/PostCtrls.tsx:216 msgid "Like" msgstr "Mi piace" @@ -2101,34 +2041,30 @@ msgstr "Mi piace" msgid "Like this feed" msgstr "Metti mi piace a questo feed" -#: src/Navigation.tsx:197 +#: src/Navigation.tsx:199 msgid "Liked by" -msgstr "Piaciuto a" +msgstr "Piace a" #: src/view/screens/PostLikedBy.tsx:27 #: src/view/screens/ProfileFeedLikedBy.tsx:27 msgid "Liked By" -msgstr "" +msgstr "Piace A" #: src/view/com/feeds/FeedSourceCard.tsx:279 msgid "Liked by {0} {1}" -msgstr "È piaciuto a {0} {1}" +msgstr "Piace a {0} {1}" #: src/view/screens/ProfileFeed.tsx:606 msgid "Liked by {likeCount} {0}" -msgstr "È piaciuto a {likeCount} {0}" +msgstr "Piace a {likeCount} {0}" #: src/view/com/notifications/FeedItem.tsx:170 msgid "liked your custom feed" -msgstr "" - -#: src/view/com/notifications/FeedItem.tsx:171 -#~ msgid "liked your custom feed{0}" -#~ msgstr "è piaciuto il feed personalizzato{0}" +msgstr "piace il tuo feed personalizzato" #: src/view/com/notifications/FeedItem.tsx:155 msgid "liked your post" -msgstr "è piaciuto il tuo post" +msgstr "piace il tuo post" #: src/view/screens/Profile.tsx:183 msgid "Likes" @@ -2138,7 +2074,7 @@ msgstr "Mi piace" msgid "Likes on this post" msgstr "Mi Piace in questo post" -#: src/Navigation.tsx:166 +#: src/Navigation.tsx:168 msgid "List" msgstr "Lista" @@ -2174,7 +2110,7 @@ msgstr "Lista sbloccata" msgid "List unmuted" msgstr "Lista non mutata" -#: src/Navigation.tsx:110 +#: src/Navigation.tsx:112 #: src/view/screens/Profile.tsx:185 #: src/view/shell/desktop/LeftNav.tsx:379 #: src/view/shell/Drawer.tsx:492 @@ -2206,33 +2142,28 @@ msgstr "Caricamento..." #~ msgid "Local dev server" #~ msgstr "Server di sviluppo locale" -#: src/Navigation.tsx:207 +#: src/Navigation.tsx:209 msgid "Log" msgstr "Log" -#: src/screens/Deactivated.tsx:149 -#: src/screens/Deactivated.tsx:152 -#: src/screens/Deactivated.tsx:178 -#: src/screens/Deactivated.tsx:181 +#: src/screens/Deactivated.tsx:149 src/screens/Deactivated.tsx:152 +#: src/screens/Deactivated.tsx:178 src/screens/Deactivated.tsx:181 msgid "Log out" -msgstr "" +msgstr "Disconnetta l'account" #: src/view/screens/Moderation.tsx:155 msgid "Logged-out visibility" -msgstr "Visibilità degli utenti non connettati" +msgstr "Visibilità degli utenti disconnessi" #: src/view/com/auth/login/ChooseAccountForm.tsx:133 msgid "Login to account that is not listed" msgstr "Accedi all'account che non è nella lista" -#~ msgid "Looks like this feed is only available to users with a Bluesky account. Please sign up or sign in to view this feed!" -#~ msgstr "Parece que este canal de noticias sólo está disponible para usuarios con una cuenta Bluesky. Por favor, ¡regÃstrate o inicia sesión para ver este canal!" - #: src/view/com/modals/LinkWarning.tsx:65 msgid "Make sure this is where you intend to go!" msgstr "Assicurati che questo sia dove intendi andare!" -#: src/components/dialogs/MutedWords.tsx:71 +#: src/components/dialogs/MutedWords.tsx:83 msgid "Manage your muted words and tags" msgstr "" @@ -2256,23 +2187,19 @@ msgstr "utenti menzionati" msgid "Mentioned users" msgstr "Utenti menzionati" -#: src/view/com/util/ViewHeader.tsx:81 +#: src/view/com/util/ViewHeader.tsx:87 #: src/view/screens/Search/Search.tsx:646 msgid "Menu" msgstr "Menù" -#~ msgid "Message from server" -#~ msgstr "Missatge del servidor" - #: src/view/com/posts/FeedErrorMessage.tsx:197 msgid "Message from server: {0}" msgstr "Messaggio dal server: {0}" -#: src/Navigation.tsx:115 +#: src/Navigation.tsx:117 #: src/view/screens/Moderation.tsx:66 #: src/view/screens/Settings/index.tsx:625 -#: src/view/shell/desktop/LeftNav.tsx:397 -#: src/view/shell/Drawer.tsx:511 +#: src/view/shell/desktop/LeftNav.tsx:397 src/view/shell/Drawer.tsx:511 #: src/view/shell/Drawer.tsx:512 msgid "Moderation" msgstr "Moderazione" @@ -2282,13 +2209,13 @@ msgstr "Moderazione" msgid "Moderation list by {0}" msgstr "Lista di moderazione di {0}" -#: src/view/screens/ProfileList.tsx:774 +#: src/view/screens/ProfileList.tsx:775 msgid "Moderation list by <0/>" msgstr "Lista di moderazione di <0/>" #: src/view/com/lists/ListCard.tsx:91 #: src/view/com/modals/UserAddRemoveLists.tsx:204 -#: src/view/screens/ProfileList.tsx:772 +#: src/view/screens/ProfileList.tsx:773 msgid "Moderation list by you" msgstr "Le tue liste di moderazione" @@ -2304,7 +2231,7 @@ msgstr "Lista di moderazione aggiornata" msgid "Moderation lists" msgstr "Liste di moderazione" -#: src/Navigation.tsx:120 +#: src/Navigation.tsx:122 #: src/view/screens/ModerationModlists.tsx:58 msgid "Moderation Lists" msgstr "Liste di Moderazione" @@ -2317,7 +2244,7 @@ msgstr "Impostazioni di moderazione" msgid "Moderator has chosen to set a general warning on the content." msgstr "Il moderatore ha scelto di mettere un avviso generale sul contenuto." -#: src/view/shell/desktop/Feeds.tsx:63 +#: src/view/shell/desktop/Feeds.tsx:65 msgid "More feeds" msgstr "Altri feed" @@ -2328,8 +2255,8 @@ msgid "More options" msgstr "Altre opzioni" #: src/view/com/util/forms/PostDropdownBtn.tsx:315 -msgid "More post options" -msgstr "Altre impostazioni per il post" +#~ msgid "More post options" +#~ msgstr "Altre impostazioni per il post" #: src/view/screens/PreferencesThreads.tsx:82 msgid "Most-liked replies first" @@ -2339,11 +2266,11 @@ msgstr "Dai priorità alle risposte con più likes" msgid "Must be at least 3 characters" msgstr "" -#: src/components/TagMenu/index.tsx:253 +#: src/components/TagMenu/index.tsx:249 msgid "Mute" msgstr "" -#: src/components/TagMenu/index.web.tsx:91 +#: src/components/TagMenu/index.web.tsx:105 msgid "Mute {truncatedTag}" msgstr "" @@ -2355,15 +2282,19 @@ msgstr "Silenziare Account" msgid "Mute accounts" msgstr "Silenziare accounts" -#: src/components/TagMenu/index.tsx:211 -msgid "Mute all {tag} posts" +#: src/components/TagMenu/index.tsx:209 +msgid "Mute all {displayTag} posts" msgstr "" -#: src/components/dialogs/MutedWords.tsx:131 +#: src/components/TagMenu/index.tsx:211 +#~ msgid "Mute all {tag} posts" +#~ msgstr "" + +#: src/components/dialogs/MutedWords.tsx:149 msgid "Mute in tags only" msgstr "" -#: src/components/dialogs/MutedWords.tsx:116 +#: src/components/dialogs/MutedWords.tsx:134 msgid "Mute in text & tags" msgstr "" @@ -2379,19 +2310,21 @@ msgstr "Vuoi silenziare queste liste?" msgid "Mute this List" msgstr "Silenzia questa Lista" -#: src/components/dialogs/MutedWords.tsx:109 +#: src/components/dialogs/MutedWords.tsx:127 msgid "Mute this word in post text and tags" msgstr "" -#: src/components/dialogs/MutedWords.tsx:124 +#: src/components/dialogs/MutedWords.tsx:142 msgid "Mute this word in tags only" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:202 +#: src/view/com/util/forms/PostDropdownBtn.tsx:251 +#: src/view/com/util/forms/PostDropdownBtn.tsx:257 msgid "Mute thread" msgstr "Silenzia questa discussione" -#: src/view/com/util/forms/PostDropdownBtn.tsx:216 +#: src/view/com/util/forms/PostDropdownBtn.tsx:267 +#: src/view/com/util/forms/PostDropdownBtn.tsx:269 msgid "Mute words & tags" msgstr "" @@ -2403,7 +2336,7 @@ msgstr "Silenziato" msgid "Muted accounts" msgstr "Account silenziato" -#: src/Navigation.tsx:125 +#: src/Navigation.tsx:127 #: src/view/screens/ModerationMutedAccounts.tsx:107 msgid "Muted Accounts" msgstr "Accounts Silenziati" @@ -2438,7 +2371,7 @@ msgstr "I miei Feeds Salvati" #: src/view/com/auth/server-input/index.tsx:118 msgid "my-server.com" -msgstr "" +msgstr "my-server.com" #: src/view/com/modals/AddAppPasswords.tsx:179 #: src/view/com/modals/CreateOrEditList.tsx:290 @@ -2451,7 +2384,7 @@ msgstr "Il nome è obbligatorio" #: src/screens/Onboarding/index.tsx:25 msgid "Nature" -msgstr "" +msgstr "Natura" #: src/view/com/auth/login/ForgotPasswordForm.tsx:190 #: src/view/com/auth/login/ForgotPasswordForm.tsx:219 @@ -2477,20 +2410,20 @@ msgstr "Non perdere mai l'accesso ai tuoi follower e ai tuoi dati." #: src/screens/Onboarding/StepFinished.tsx:119 msgid "Never lose access to your followers or data." -msgstr "" +msgstr "Non perdere mai l'accesso ai tuoi follower o ai tuoi dati." -#: src/components/dialogs/MutedWords.tsx:244 +#: src/components/dialogs/MutedWords.tsx:293 msgid "Nevermind" msgstr "" #: src/view/screens/Lists.tsx:76 msgctxt "action" msgid "New" -msgstr "Nuovo" +msgstr "Nuova" #: src/view/screens/ModerationModlists.tsx:78 msgid "New" -msgstr "Nuovo" +msgstr "Nuova" #: src/view/com/modals/CreateOrEditList.tsx:252 msgid "New Moderation List" @@ -2502,7 +2435,7 @@ msgstr "Nuovo Password" #: src/view/com/modals/ChangePassword.tsx:215 msgid "New Password" -msgstr "" +msgstr "Nuovo Password" #: src/view/com/feeds/FeedPage.tsx:126 msgctxt "action" @@ -2524,12 +2457,9 @@ msgctxt "action" msgid "New Post" msgstr "Nuovo post" -#~ msgid "New Post" -#~ msgstr "Nova publicació" - #: src/view/com/modals/CreateOrEditList.tsx:247 msgid "New User List" -msgstr "Nuova lista utenti" +msgstr "Nuova lista" #: src/view/screens/PreferencesThreads.tsx:79 msgid "Newest replies first" @@ -2537,7 +2467,7 @@ msgstr "Mostrare prima le risposte più recenti" #: src/screens/Onboarding/index.tsx:23 msgid "News" -msgstr "" +msgstr "Notizie" #: src/view/com/auth/create/CreateAccount.tsx:172 #: src/view/com/auth/login/ForgotPasswordForm.tsx:182 @@ -2570,7 +2500,7 @@ msgid "No" msgstr "No" #: src/view/screens/ProfileFeed.tsx:584 -#: src/view/screens/ProfileList.tsx:754 +#: src/view/screens/ProfileList.tsx:755 msgid "No description" msgstr "Senza descrizione" @@ -2587,6 +2517,10 @@ msgstr "Ancora nessuna notifica!" msgid "No result" msgstr "Nessun risultato" +#: src/components/Lists.tsx:192 +msgid "No results found" +msgstr "" + #: src/view/screens/Feeds.tsx:495 msgid "No results found for \"{query}\"" msgstr "Nessun risultato trovato per \"{query}\"" @@ -2609,7 +2543,7 @@ msgstr "Nessuno" msgid "Not Applicable." msgstr "Non applicabile." -#: src/Navigation.tsx:105 +#: src/Navigation.tsx:107 #: src/view/screens/Profile.tsx:106 msgid "Not Found" msgstr "Non trovato" @@ -2623,15 +2557,14 @@ msgstr "Non adesso" msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites." msgstr "Nota: Bluesky è una rete aperta e pubblica. Questa impostazione limita solo la visibilità dei tuoi contenuti sull'app e sul sito Web di Bluesky e altre app potrebbero non rispettare questa impostazione. I tuoi contenuti potrebbero comunque essere mostrati agli utenti disconnessi da altre app e siti web." -#: src/Navigation.tsx:450 +#: src/Navigation.tsx:457 #: src/view/screens/Notifications.tsx:124 #: src/view/screens/Notifications.tsx:148 #: src/view/shell/bottom-bar/BottomBar.tsx:205 -#: src/view/shell/desktop/LeftNav.tsx:361 -#: src/view/shell/Drawer.tsx:435 +#: src/view/shell/desktop/LeftNav.tsx:361 src/view/shell/Drawer.tsx:435 #: src/view/shell/Drawer.tsx:436 msgid "Notifications" -msgstr "Notifica" +msgstr "Notifiche" #: src/view/com/modals/SelfLabel.tsx:103 msgid "Nudity" @@ -2643,7 +2576,7 @@ msgstr "Oh no!" #: src/screens/Onboarding/StepInterests/index.tsx:128 msgid "Oh no! Something went wrong." -msgstr "" +msgstr "Oh no! Qualcosa è andato storto." #: src/view/com/auth/login/PasswordUpdatedForm.tsx:41 msgid "Okay" @@ -2651,7 +2584,7 @@ msgstr "Va bene" #: src/view/screens/PreferencesThreads.tsx:78 msgid "Oldest replies first" -msgstr "Prima le risposte più vecchie" +msgstr "Mostrare prima le risposte più vecchie" #: src/view/screens/Settings/index.tsx:234 msgid "Onboarding reset" @@ -2665,6 +2598,11 @@ msgstr "A una o più immagini manca il testo alternativo." msgid "Only {0} can reply." msgstr "Solo {0} può rispondere." +#: src/components/Lists.tsx:82 +msgid "Oops, something went wrong!" +msgstr "" + +#: src/components/Lists.tsx:188 #: src/view/screens/AppPasswords.tsx:65 #: src/view/screens/Profile.tsx:106 msgid "Oops!" @@ -2672,7 +2610,7 @@ msgstr "Ops!" #: src/screens/Onboarding/StepFinished.tsx:115 msgid "Open" -msgstr "" +msgstr "Apri" #: src/view/screens/Moderation.tsx:75 msgid "Open content filtering settings" @@ -2691,10 +2629,14 @@ msgstr "Apri i links con il navigatore della app" msgid "Open muted words settings" msgstr "" -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:49 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:50 msgid "Open navigation" msgstr "Apri la navigazione" +#: src/view/com/util/forms/PostDropdownBtn.tsx:175 +msgid "Open post options menu" +msgstr "" + #: src/view/screens/Settings/index.tsx:804 msgid "Open storybook page" msgstr "Apri la pagina della cronologia" @@ -2707,7 +2649,7 @@ msgstr "Apre le {numItems} opzioni" msgid "Opens additional details for a debug entry" msgstr "Apre dettagli aggiuntivi per una debug entry" -#: src/view/com/notifications/FeedItem.tsx:348 +#: src/view/com/notifications/FeedItem.tsx:349 msgid "Opens an expanded list of users in this notification" msgstr "Apre un elenco ampliato di utenti in questa notifica" @@ -2743,10 +2685,6 @@ msgstr "Apre la lista dei followers" msgid "Opens following list" msgstr "Apre la lista di chi segui" -#: src/view/screens/Settings.tsx:412 -#~ msgid "Opens invite code list" -#~ msgstr "Apre la lista dei codici di invito" - #: src/view/com/modals/InviteCodes.tsx:172 msgid "Opens list of invite codes" msgstr "Apre la lista dei codici di invito" @@ -2767,7 +2705,7 @@ msgstr "Apre le impostazioni di moderazione" msgid "Opens password reset form" msgstr "Apre il modulo di reimpostazione della password" -#: src/view/com/home/HomeHeaderLayout.web.tsx:60 +#: src/view/com/home/HomeHeaderLayout.web.tsx:63 #: src/view/screens/Feeds.tsx:356 msgid "Opens screen to edit Saved Feeds" msgstr "Apre la schermata per modificare i feed salvati" @@ -2808,24 +2746,21 @@ msgstr "Oppure combina queste opzioni:" msgid "Other account" msgstr "Altro account" -#: src/view/com/modals/ServerInput.tsx:88 -#~ msgid "Other service" -#~ msgstr "Altro servizio" - #: src/view/com/composer/select-language/SelectLangBtn.tsx:91 msgid "Other..." msgstr "Altro..." +#: src/components/Lists.tsx:194 #: src/view/screens/NotFound.tsx:45 msgid "Page not found" msgstr "Pagina non trovata" #: src/view/screens/NotFound.tsx:42 msgid "Page Not Found" -msgstr "" +msgstr "Pagina non trovata" -#: src/view/com/auth/create/Step1.tsx:214 -#: src/view/com/auth/create/Step1.tsx:224 +#: src/view/com/auth/create/Step1.tsx:191 +#: src/view/com/auth/create/Step1.tsx:201 #: src/view/com/auth/login/LoginForm.tsx:226 #: src/view/com/auth/login/SetNewPasswordForm.tsx:161 #: src/view/com/modals/DeleteAccount.tsx:202 @@ -2840,11 +2775,11 @@ msgstr "Password aggiornata" msgid "Password updated!" msgstr "Password aggiornata!" -#: src/Navigation.tsx:160 +#: src/Navigation.tsx:162 msgid "People followed by @{0}" msgstr "Persone seguite da @{0}" -#: src/Navigation.tsx:153 +#: src/Navigation.tsx:155 msgid "People following @{0}" msgstr "Persone che seguono @{0}" @@ -2858,7 +2793,7 @@ msgstr "L'autorizzazione per accedere la cartella delle immagini è stata negata #: src/screens/Onboarding/index.tsx:31 msgid "Pets" -msgstr "" +msgstr "Animali di compagnia" #: src/view/com/auth/create/Step2.tsx:183 #~ msgid "Phone number" @@ -2871,11 +2806,11 @@ msgstr "Immagini per adulti." #: src/view/screens/ProfileFeed.tsx:354 #: src/view/screens/ProfileList.tsx:581 msgid "Pin to home" -msgstr "Fissa sulla pagina principale" +msgstr "Fissa sulla home page" #: src/view/screens/SavedFeeds.tsx:88 msgid "Pinned Feeds" -msgstr "Feed Fissati" +msgstr "Feeds Fissi" #: src/view/com/util/post-embeds/ExternalGifEmbed.tsx:111 msgid "Play {0}" @@ -2918,6 +2853,10 @@ msgstr "Inserisci un nome per la password dell'app. Tutti gli spazi non sono con msgid "Please enter a unique name for this App Password or use our randomly generated one." msgstr "Inserisci un nome unico per la password dell'app o utilizzane uno generato automaticamente." +#: src/components/dialogs/MutedWords.tsx:68 +msgid "Please enter a valid word, tag, or phrase to mute" +msgstr "" + #: src/view/com/auth/create/state.ts:170 #~ msgid "Please enter the code you received by SMS." #~ msgstr "Inserisci il codice che hai ricevuto via SMS." @@ -2939,9 +2878,6 @@ msgstr "Inserisci anche la tua password:" msgid "Please tell us why you think this content warning was incorrectly applied!" msgstr "Spiegaci perché ritieni che questo avviso sui contenuti sia stato applicato in modo errato!" -#~ msgid "Please tell us why you think this decision was incorrect." -#~ msgstr "Por favor, dinos por qué crees que esta decisión fue incorrecta." - #: src/view/com/modals/VerifyEmail.tsx:101 msgid "Please Verify Your Email" msgstr "Verifica la tua email" @@ -2952,7 +2888,7 @@ msgstr "Attendi il caricamento della scheda di collegamento" #: src/screens/Onboarding/index.tsx:37 msgid "Politics" -msgstr "" +msgstr "Politica" #: src/view/com/modals/SelfLabel.tsx:111 msgid "Porn" @@ -2976,13 +2912,13 @@ msgstr "Post" msgid "Post by {0}" msgstr "Pubblicato da {0}" -#: src/Navigation.tsx:172 -#: src/Navigation.tsx:179 -#: src/Navigation.tsx:186 +#: src/Navigation.tsx:174 +#: src/Navigation.tsx:181 +#: src/Navigation.tsx:188 msgid "Post by @{0}" msgstr "Pubblicato da @{0}" -#: src/view/com/util/forms/PostDropdownBtn.tsx:90 +#: src/view/com/util/forms/PostDropdownBtn.tsx:108 msgid "Post deleted" msgstr "Post eliminato" @@ -3002,7 +2938,7 @@ msgstr "Lingue del post" msgid "Post not found" msgstr "Post non trovato" -#: src/components/TagMenu/index.tsx:257 +#: src/components/TagMenu/index.tsx:253 msgid "posts" msgstr "" @@ -3010,7 +2946,7 @@ msgstr "" msgid "Posts" msgstr "Post" -#: src/components/dialogs/MutedWords.tsx:77 +#: src/components/dialogs/MutedWords.tsx:90 msgid "Posts can be muted based on their text, their tags, or both." msgstr "" @@ -3039,7 +2975,7 @@ msgstr "Dai priorità a quelli che segui" msgid "Privacy" msgstr "Privacy" -#: src/Navigation.tsx:217 +#: src/Navigation.tsx:219 #: src/view/screens/PrivacyPolicy.tsx:29 #: src/view/screens/Settings/index.tsx:891 #: src/view/shell/Drawer.tsx:262 @@ -3051,10 +2987,8 @@ msgid "Processing..." msgstr "Elaborazione in corso…" #: src/view/shell/bottom-bar/BottomBar.tsx:247 -#: src/view/shell/desktop/LeftNav.tsx:415 -#: src/view/shell/Drawer.tsx:70 -#: src/view/shell/Drawer.tsx:546 -#: src/view/shell/Drawer.tsx:547 +#: src/view/shell/desktop/LeftNav.tsx:415 src/view/shell/Drawer.tsx:70 +#: src/view/shell/Drawer.tsx:546 src/view/shell/Drawer.tsx:547 msgid "Profile" msgstr "Profilo" @@ -3068,7 +3002,7 @@ msgstr "Proteggi il tuo account verificando la tua email." #: src/screens/Onboarding/StepFinished.tsx:101 msgid "Public" -msgstr "" +msgstr "Pubblico" #: src/view/screens/ModerationModlists.tsx:61 msgid "Public, shareable lists of users to mute or block in bulk." @@ -3076,7 +3010,7 @@ msgstr "Elenchi pubblici e condivisibili di utenti da disattivare o bloccare in #: src/view/screens/Lists.tsx:61 msgid "Public, shareable lists which can drive feeds." -msgstr "Elenchi pubblici e condivisibili che possono gestire i feeds." +msgstr "Liste pubbliche e condivisibili che possono impulsare i feeds." #: src/view/com/composer/Composer.tsx:342 msgid "Publish post" @@ -3100,9 +3034,6 @@ msgctxt "action" msgid "Quote Post" msgstr "Cita il post" -#~ msgid "Quote Post" -#~ msgstr "Cita una publicació" - #: src/view/screens/PreferencesThreads.tsx:86 msgid "Random (aka \"Poster's Roulette\")" msgstr "Selezione a caso (nota anche come \"Poster's Roulette\")" @@ -3119,12 +3050,11 @@ msgstr "Feeds consigliati" msgid "Recommended Users" msgstr "Utenti consigliati" -#: src/components/dialogs/MutedWords.tsx:249 +#: src/components/dialogs/MutedWords.tsx:298 #: src/view/com/modals/ListAddRemoveUsers.tsx:264 #: src/view/com/modals/SelfLabel.tsx:83 #: src/view/com/modals/UserAddRemoveLists.tsx:219 -#: src/view/com/util/UserAvatar.tsx:285 -#: src/view/com/util/UserBanner.tsx:91 +#: src/view/com/util/UserAvatar.tsx:285 src/view/com/util/UserBanner.tsx:91 msgid "Remove" msgstr "Rimuovi" @@ -3157,7 +3087,7 @@ msgstr "Rimuovi l'immagine" msgid "Remove image preview" msgstr "Rimuovi l'anteprima dell'immagine" -#: src/components/dialogs/MutedWords.tsx:294 +#: src/components/dialogs/MutedWords.tsx:343 msgid "Remove mute word from your list" msgstr "" @@ -3198,7 +3128,7 @@ msgstr "Le risposte a questo thread sono disabilitate" #: src/view/com/composer/Composer.tsx:355 msgctxt "action" msgid "Reply" -msgstr "Rispondi" +msgstr "Risposta" #: src/view/screens/PreferencesFollowingFeed.tsx:144 msgid "Reply Filters" @@ -3208,7 +3138,7 @@ msgstr "Filtri di risposta" #: src/view/com/posts/FeedItem.tsx:287 msgctxt "description" msgid "Reply to <0/>" -msgstr "Rispondi a <0/>" +msgstr "In risposta a <0/>" #: src/view/com/modals/report/Modal.tsx:166 msgid "Report {collectionName}" @@ -3227,12 +3157,12 @@ msgid "Report List" msgstr "Segnala la lista" #: src/view/com/modals/report/SendReportButton.tsx:37 -#: src/view/com/util/forms/PostDropdownBtn.tsx:255 +#: src/view/com/util/forms/PostDropdownBtn.tsx:301 +#: src/view/com/util/forms/PostDropdownBtn.tsx:309 msgid "Report post" msgstr "Segnala il post" -#: src/view/com/modals/Repost.tsx:43 -#: src/view/com/modals/Repost.tsx:48 +#: src/view/com/modals/Repost.tsx:43 src/view/com/modals/Repost.tsx:48 #: src/view/com/modals/Repost.tsx:53 #: src/view/com/util/post-ctrls/RepostButton.tsx:61 msgctxt "action" @@ -3249,32 +3179,24 @@ msgid "Repost or quote post" msgstr "Ripubblicare o citare il post" #: src/view/screens/PostRepostedBy.tsx:27 -#~ msgid "Reposted by" -#~ msgstr "Ripubblicato da" - -#: src/view/screens/PostRepostedBy.tsx:27 msgid "Reposted By" -msgstr "" +msgstr "Repost di" #: src/view/com/posts/FeedItem.tsx:207 msgid "Reposted by {0}" -msgstr "" - -#: src/view/com/posts/FeedItem.tsx:206 -#~ msgid "Reposted by {0})" -#~ msgstr "Ripubblicato da {0})" +msgstr "Repost di {0}" #: src/view/com/posts/FeedItem.tsx:224 msgid "Reposted by <0/>" -msgstr "Ripubblicato da <0/>" +msgstr "Repost di <0/>" #: src/view/com/notifications/FeedItem.tsx:162 msgid "reposted your post" -msgstr "ripubblicato il tuo post" +msgstr "reposted il tuo post" #: src/view/com/post-thread/PostThreadItem.tsx:188 msgid "Reposts of this post" -msgstr "Ripubblicazione di questo post" +msgstr "Repost di questo post" #: src/view/com/modals/ChangeEmail.tsx:181 #: src/view/com/modals/ChangeEmail.tsx:183 @@ -3288,13 +3210,13 @@ msgstr "Richiedi un cambio" #: src/view/com/modals/ChangePassword.tsx:239 #: src/view/com/modals/ChangePassword.tsx:241 msgid "Request Code" -msgstr "" +msgstr "Richiedi il codice" #: src/view/screens/Settings/index.tsx:456 msgid "Require alt text before posting" msgstr "Richiedi il testo alternativo prima di pubblicare" -#: src/view/com/auth/create/Step1.tsx:153 +#: src/view/com/auth/create/Step1.tsx:146 msgid "Required for this provider" msgstr "Obbligatorio per questo operatore" @@ -3305,7 +3227,7 @@ msgstr "Reimpostare il codice" #: src/view/com/modals/ChangePassword.tsx:190 msgid "Reset Code" -msgstr "" +msgstr "Reimposta il Codice" #: src/view/screens/Settings/index.tsx:824 msgid "Reset onboarding" @@ -3359,7 +3281,7 @@ msgstr "Riprova" #~ msgid "Retry." #~ msgstr "Riprova." -#: src/view/screens/ProfileList.tsx:898 +#: src/view/screens/ProfileList.tsx:903 msgid "Return to previous page" msgstr "Ritorna alla pagina precedente" @@ -3412,13 +3334,13 @@ msgstr "Salva la modifica del cambio dell'utente in {handle}" #: src/screens/Onboarding/index.tsx:36 msgid "Science" -msgstr "" +msgstr "Scienza" -#: src/view/screens/ProfileList.tsx:854 +#: src/view/screens/ProfileList.tsx:859 msgid "Scroll to top" msgstr "Scorri verso l'alto" -#: src/Navigation.tsx:440 +#: src/Navigation.tsx:447 #: src/view/com/auth/LoggedOut.tsx:122 #: src/view/com/modals/ListAddRemoveUsers.tsx:75 #: src/view/com/util/forms/SearchInput.tsx:67 @@ -3427,10 +3349,8 @@ msgstr "Scorri verso l'alto" #: src/view/screens/Search/Search.tsx:668 #: src/view/screens/Search/Search.tsx:686 #: src/view/shell/bottom-bar/BottomBar.tsx:159 -#: src/view/shell/desktop/LeftNav.tsx:324 -#: src/view/shell/desktop/Search.tsx:214 -#: src/view/shell/desktop/Search.tsx:223 -#: src/view/shell/Drawer.tsx:362 +#: src/view/shell/desktop/LeftNav.tsx:324 src/view/shell/desktop/Search.tsx:214 +#: src/view/shell/desktop/Search.tsx:223 src/view/shell/Drawer.tsx:362 #: src/view/shell/Drawer.tsx:363 msgid "Search" msgstr "Cerca" @@ -3441,13 +3361,21 @@ msgid "Search for \"{query}\"" msgstr "Cerca \"{query}\"" #: src/components/TagMenu/index.tsx:145 -msgid "Search for all posts by @{authorHandle} with tag {tag}" +msgid "Search for all posts by @{authorHandle} with tag {displayTag}" msgstr "" -#: src/components/TagMenu/index.tsx:90 -msgid "Search for all posts with tag {tag}" +#: src/components/TagMenu/index.tsx:145 +#~ msgid "Search for all posts by @{authorHandle} with tag {tag}" +#~ msgstr "" + +#: src/components/TagMenu/index.tsx:94 +msgid "Search for all posts with tag {displayTag}" msgstr "" +#: src/components/TagMenu/index.tsx:90 +#~ msgid "Search for all posts with tag {tag}" +#~ msgstr "" + #: src/view/com/auth/LoggedOut.tsx:104 #: src/view/com/auth/LoggedOut.tsx:105 #: src/view/com/modals/ListAddRemoveUsers.tsx:70 @@ -3458,22 +3386,30 @@ msgstr "Cerca utenti" msgid "Security Step Required" msgstr "Passaggio di sicurezza obbligatorio" -#: src/components/TagMenu/index.web.tsx:50 +#: src/components/TagMenu/index.web.tsx:66 msgid "See {truncatedTag} posts" msgstr "" -#: src/components/TagMenu/index.web.tsx:67 +#: src/components/TagMenu/index.web.tsx:83 msgid "See {truncatedTag} posts by user" msgstr "" #: src/components/TagMenu/index.tsx:128 -msgid "See <0>{tag}</0> posts" +msgid "See <0>{displayTag}</0> posts" msgstr "" -#: src/components/TagMenu/index.tsx:189 -msgid "See <0>{tag}</0> posts by this user" +#: src/components/TagMenu/index.tsx:187 +msgid "See <0>{displayTag}</0> posts by this user" msgstr "" +#: src/components/TagMenu/index.tsx:128 +#~ msgid "See <0>{tag}</0> posts" +#~ msgstr "" + +#: src/components/TagMenu/index.tsx:189 +#~ msgid "See <0>{tag}</0> posts by this user" +#~ msgstr "" + #: src/view/screens/SavedFeeds.tsx:163 msgid "See this guide" msgstr "Consulta questa guida" @@ -3486,10 +3422,6 @@ msgstr "Scopri cosa c'è dopo" msgid "Select {item}" msgstr "Seleziona {item}" -#: src/view/com/modals/ServerInput.tsx:75 -#~ msgid "Select Bluesky Social" -#~ msgstr "Seleziona Bluesky Social" - #: src/view/com/auth/login/Login.tsx:117 msgid "Select from an existing account" msgstr "Seleziona da un account esistente" @@ -3498,26 +3430,26 @@ msgstr "Seleziona da un account esistente" msgid "Select option {i} of {numItems}" msgstr "Seleziona l'opzione {i} di {numItems}" -#: src/view/com/auth/create/Step1.tsx:103 +#: src/view/com/auth/create/Step1.tsx:96 #: src/view/com/auth/login/LoginForm.tsx:150 msgid "Select service" msgstr "Selecciona el servei" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:52 msgid "Select some accounts below to follow" -msgstr "" +msgstr "Seleziona alcuni account da seguire qui giù" #: src/view/com/auth/server-input/index.tsx:82 msgid "Select the service that hosts your data." -msgstr "" +msgstr "Seleziona il servizio che ospita i tuoi dati." #: src/screens/Onboarding/StepTopicalFeeds.tsx:96 msgid "Select topical feeds to follow from the list below" -msgstr "" +msgstr "Seleziona i feeds con temi da seguire dal seguente elenco" #: src/screens/Onboarding/StepModeration/index.tsx:75 msgid "Select what you want to see (or not see), and we’ll handle the rest." -msgstr "" +msgstr "Seleziona ciò che vuoi vedere (o non vedere) e noi gestiremo il resto." #: src/view/screens/LanguageSettings.tsx:281 msgid "Select which languages you want your subscribed feeds to include. If none are selected, all languages will be shown." @@ -3529,7 +3461,7 @@ msgstr "Seleziona la lingua dell'app per il testo predefinito da visualizzare ne #: src/screens/Onboarding/StepInterests/index.tsx:196 msgid "Select your interests from the options below" -msgstr "" +msgstr "Seleziona i tuoi interessi dalle seguenti opzioni" #: src/view/com/auth/create/Step2.tsx:155 #~ msgid "Select your phone's country" @@ -3541,11 +3473,11 @@ msgstr "Seleziona la tua lingua preferita per le traduzioni nel tuo feed." #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:116 msgid "Select your primary algorithmic feeds" -msgstr "" +msgstr "Seleziona i tuoi feed algoritmici principali" #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:142 msgid "Select your secondary algorithmic feeds" -msgstr "" +msgstr "Seleziona i tuoi feed algoritmici secondari" #: src/view/com/modals/VerifyEmail.tsx:202 #: src/view/com/modals/VerifyEmail.tsx:204 @@ -3561,11 +3493,7 @@ msgctxt "action" msgid "Send Email" msgstr "Invia email" -#~ msgid "Send Email" -#~ msgstr "Envia correu" - -#: src/view/shell/Drawer.tsx:295 -#: src/view/shell/Drawer.tsx:316 +#: src/view/shell/Drawer.tsx:295 src/view/shell/Drawer.tsx:316 msgid "Send feedback" msgstr "Invia feedback" @@ -3579,7 +3507,7 @@ msgstr "Invia un'email con il codice di conferma per la cancellazione dell'accou #: src/view/com/auth/server-input/index.tsx:110 msgid "Server address" -msgstr "" +msgstr "Indirizzo del server" #: src/view/com/modals/ContentFilteringSettings.tsx:311 msgid "Set {value} for {labelGroup} content moderation policy" @@ -3605,17 +3533,17 @@ msgstr "Imposta il colore del tema basato sulle impostazioni del tuo sistema" #: src/view/screens/Settings/index.tsx:514 msgid "Set dark theme to the dark theme" -msgstr "" +msgstr "Imposta il tema scuro sul tema scuro" #: src/view/screens/Settings/index.tsx:507 msgid "Set dark theme to the dim theme" -msgstr "" +msgstr "Imposta il tema scuro sul tema scuro" #: src/view/com/auth/login/SetNewPasswordForm.tsx:104 msgid "Set new password" msgstr "Imposta una nuova password" -#: src/view/com/auth/create/Step1.tsx:225 +#: src/view/com/auth/create/Step1.tsx:202 msgid "Set password" msgstr "Imposta la password" @@ -3645,7 +3573,7 @@ msgstr "" #: src/screens/Onboarding/Layout.tsx:50 msgid "Set up your account" -msgstr "" +msgstr "Configura il tuo account" #: src/view/com/modals/ChangeHandle.tsx:266 msgid "Sets Bluesky username" @@ -3659,12 +3587,12 @@ msgstr "Imposta l'email per la reimpostazione della password" msgid "Sets hosting provider for password reset" msgstr "Imposta il provider del hosting per la reimpostazione della password" -#: src/view/com/auth/create/Step1.tsx:104 +#: src/view/com/auth/create/Step1.tsx:97 #: src/view/com/auth/login/LoginForm.tsx:151 msgid "Sets server for the Bluesky client" msgstr "Imposta il server per il client Bluesky" -#: src/Navigation.tsx:135 +#: src/Navigation.tsx:137 #: src/view/screens/Settings/index.tsx:294 #: src/view/shell/desktop/LeftNav.tsx:433 #: src/view/shell/Drawer.tsx:567 @@ -3682,7 +3610,9 @@ msgid "Share" msgstr "Condividi" #: src/view/com/profile/ProfileHeader.tsx:295 -#: src/view/com/util/forms/PostDropdownBtn.tsx:184 +#: src/view/com/util/forms/PostDropdownBtn.tsx:231 +#: src/view/com/util/forms/PostDropdownBtn.tsx:237 +#: src/view/com/util/post-ctrls/PostCtrls.tsx:215 #: src/view/screens/ProfileList.tsx:418 msgid "Share" msgstr "Condividi" @@ -3731,15 +3661,15 @@ msgstr "Mostra post con citazioni" #: src/screens/Onboarding/StepFollowingFeed.tsx:118 msgid "Show quote-posts in Following feed" -msgstr "" +msgstr "Mostra i post con citazioni nel feed Seguiti" #: src/screens/Onboarding/StepFollowingFeed.tsx:134 msgid "Show quotes in Following" -msgstr "" +msgstr "Mostra le citazioni in Seguiti" #: src/screens/Onboarding/StepFollowingFeed.tsx:94 msgid "Show re-posts in Following feed" -msgstr "" +msgstr "Mostra re-post nel feed Seguiti" #: src/view/screens/PreferencesFollowingFeed.tsx:119 msgid "Show Replies" @@ -3751,11 +3681,11 @@ msgstr "Mostra le risposte delle persone che segui prima delle altre risposte." #: src/screens/Onboarding/StepFollowingFeed.tsx:86 msgid "Show replies in Following" -msgstr "" +msgstr "Mostra le risposte in Seguiti" #: src/screens/Onboarding/StepFollowingFeed.tsx:70 msgid "Show replies in Following feed" -msgstr "" +msgstr "Mostra le risposte nel feed Seguiti" #: src/view/screens/PreferencesFollowingFeed.tsx:70 msgid "Show replies with at least {value} {0}" @@ -3767,14 +3697,14 @@ msgstr "Mostra ripubblicazioni" #: src/screens/Onboarding/StepFollowingFeed.tsx:110 msgid "Show reposts in Following" -msgstr "" +msgstr "Mostra i re-repost in Seguiti" #: src/view/com/util/moderation/ContentHider.tsx:67 #: src/view/com/util/moderation/PostHider.tsx:61 msgid "Show the content" msgstr "Mostra il contenuto" -#: src/view/com/notifications/FeedItem.tsx:346 +#: src/view/com/notifications/FeedItem.tsx:347 msgid "Show users" msgstr "Mostra utenti" @@ -3788,16 +3718,14 @@ msgid "Shows posts from {0} in your feed" msgstr "Mostra i post di {0} nel tuo feed" #: src/view/com/auth/HomeLoggedOutCTA.tsx:70 -#: src/view/com/auth/login/Login.tsx:98 -#: src/view/com/auth/SplashScreen.tsx:79 +#: src/view/com/auth/login/Login.tsx:98 src/view/com/auth/SplashScreen.tsx:79 #: src/view/shell/bottom-bar/BottomBar.tsx:285 #: src/view/shell/bottom-bar/BottomBar.tsx:286 #: src/view/shell/bottom-bar/BottomBar.tsx:288 #: src/view/shell/bottom-bar/BottomBarWeb.tsx:178 #: src/view/shell/bottom-bar/BottomBarWeb.tsx:179 #: src/view/shell/bottom-bar/BottomBarWeb.tsx:181 -#: src/view/shell/NavSignupCard.tsx:58 -#: src/view/shell/NavSignupCard.tsx:59 +#: src/view/shell/NavSignupCard.tsx:58 src/view/shell/NavSignupCard.tsx:59 msgid "Sign in" msgstr "Accedi" @@ -3825,7 +3753,7 @@ msgstr "Accedere a" #: src/view/screens/Settings/index.tsx:100 #: src/view/screens/Settings/index.tsx:103 msgid "Sign out" -msgstr "Disconnettiti" +msgstr "Disconnetta" #: src/view/shell/bottom-bar/BottomBar.tsx:275 #: src/view/shell/bottom-bar/BottomBar.tsx:276 @@ -3833,8 +3761,7 @@ msgstr "Disconnettiti" #: src/view/shell/bottom-bar/BottomBarWeb.tsx:168 #: src/view/shell/bottom-bar/BottomBarWeb.tsx:169 #: src/view/shell/bottom-bar/BottomBarWeb.tsx:171 -#: src/view/shell/NavSignupCard.tsx:49 -#: src/view/shell/NavSignupCard.tsx:50 +#: src/view/shell/NavSignupCard.tsx:49 src/view/shell/NavSignupCard.tsx:50 #: src/view/shell/NavSignupCard.tsx:52 msgid "Sign up" msgstr "Iscrizione" @@ -3867,7 +3794,7 @@ msgstr "Salta questo passo" #: src/screens/Onboarding/StepInterests/index.tsx:232 msgid "Skip this flow" -msgstr "" +msgstr "Salta questa corrente" #: src/view/com/auth/create/Step2.tsx:82 #~ msgid "SMS verification" @@ -3875,17 +3802,21 @@ msgstr "" #: src/screens/Onboarding/index.tsx:40 msgid "Software Dev" -msgstr "" +msgstr "Sviluppo Software" #: src/view/com/modals/ProfilePreview.tsx:62 #~ msgid "Something went wrong and we're not sure what." #~ msgstr "Qualcosa è andato storto ma non siamo sicuri di cosa." +#: src/components/Lists.tsx:203 +msgid "Something went wrong!" +msgstr "" + #: src/view/com/modals/Waitlist.tsx:51 -msgid "Something went wrong. Check your email and try again." -msgstr "Qualcosa è andato storto. Controlla la tua email e riprova." +#~ msgid "Something went wrong. Check your email and try again." +#~ msgstr "Qualcosa è andato storto. Controlla la tua email e riprova." -#: src/App.native.tsx:63 +#: src/App.native.tsx:66 msgid "Sorry! Your session expired. Please log in again." msgstr "Scusa! La tua sessione è scaduta. Per favore accedi di nuovo." @@ -3899,16 +3830,12 @@ msgstr "Ordina le risposte allo stesso post per:" #: src/screens/Onboarding/index.tsx:30 msgid "Sports" -msgstr "" +msgstr "Sports" #: src/view/com/modals/crop-image/CropImage.web.tsx:122 msgid "Square" msgstr "Quadrato" -#: src/view/com/modals/ServerInput.tsx:62 -#~ msgid "Staging" -#~ msgstr "Allestimento" - #: src/view/screens/Settings/index.tsx:871 msgid "Status page" msgstr "Pagina di stato" @@ -3921,7 +3848,7 @@ msgstr "Passo {0} di {numSteps}" msgid "Storage cleared, you need to restart the app now." msgstr "Spazio di archiviazione eliminato. Riavvia l'app." -#: src/Navigation.tsx:202 +#: src/Navigation.tsx:204 #: src/view/screens/Settings/index.tsx:807 msgid "Storybook" msgstr "Cronologia" @@ -3935,9 +3862,9 @@ msgid "Subscribe" msgstr "Iscriviti" #: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:173 -#: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:307 +#: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:308 msgid "Subscribe to the {0} feed" -msgstr "" +msgstr "Iscriviti a {0} feed" #: src/view/screens/ProfileList.tsx:604 msgid "Subscribe to this list" @@ -3955,16 +3882,12 @@ msgstr "Suggerito per te" msgid "Suggestive" msgstr "Suggestivo" -#: src/Navigation.tsx:212 +#: src/Navigation.tsx:214 #: src/view/screens/Support.tsx:30 #: src/view/screens/Support.tsx:33 msgid "Support" msgstr "Supporto" -#: src/view/com/modals/ProfilePreview.tsx:110 -#~ msgid "Swipe up to see more" -#~ msgstr "Scorri verso l'alto per vedere di più" - #: src/view/com/modals/SwitchAccount.tsx:117 msgid "Switch Account" msgstr "Cambia account" @@ -3987,14 +3910,18 @@ msgstr "Sistema" msgid "System log" msgstr "Registro di sistema" -#: src/components/dialogs/MutedWords.tsx:288 +#: src/components/dialogs/MutedWords.tsx:337 msgid "tag" msgstr "" -#: src/components/TagMenu/index.tsx:74 -msgid "Tag menu: {tag}" +#: src/components/TagMenu/index.tsx:78 +msgid "Tag menu: {displayTag}" msgstr "" +#: src/components/TagMenu/index.tsx:74 +#~ msgid "Tag menu: {tag}" +#~ msgstr "" + #: src/view/com/modals/crop-image/CropImage.web.tsx:112 msgid "Tall" msgstr "Alto" @@ -4005,20 +3932,20 @@ msgstr "Tocca per visualizzare completamente" #: src/screens/Onboarding/index.tsx:39 msgid "Tech" -msgstr "" +msgstr "Tecnologia" #: src/view/shell/desktop/RightNav.tsx:81 msgid "Terms" msgstr "Termini" -#: src/Navigation.tsx:222 +#: src/Navigation.tsx:224 #: src/view/screens/Settings/index.tsx:885 #: src/view/screens/TermsOfService.tsx:29 #: src/view/shell/Drawer.tsx:256 msgid "Terms of Service" msgstr "Termini di servizio" -#: src/components/dialogs/MutedWords.tsx:288 +#: src/components/dialogs/MutedWords.tsx:337 msgid "text" msgstr "" @@ -4045,7 +3972,7 @@ msgstr "La politica sul copyright è stata spostata a <0/>" #: src/screens/Onboarding/Layout.tsx:60 msgid "The following steps will help customize your Bluesky experience." -msgstr "" +msgstr "I passaggi seguenti ti aiuteranno a personalizzare la tua esperienza con Bluesky." #: src/view/com/post-thread/PostThread.tsx:517 msgid "The post may have been deleted." @@ -4059,16 +3986,13 @@ msgstr "La politica sulla privacy è stata spostata a <0/><0/>" msgid "The support form has been moved. If you need help, please <0/> or visit {HELP_DESK_URL} to get in touch with us." msgstr "Il modulo di supporto è stato spostato. Se hai bisogno di aiuto, <0/> o visita {HELP_DESK_URL} per metterti in contatto con noi." -#~ msgid "The support form has been moved. If you need help, please<0/> or visit {HELP_DESK_URL} to get in touch with us." -#~ msgstr "El formulari de suport ha estat traslladat. Si necessites ajuda, <0/> o visita {HELP_DESK_URL} per contactar amb nosaltres." - #: src/view/screens/TermsOfService.tsx:33 msgid "The Terms of Service have been moved to" msgstr "I Termini di Servizio sono stati spostati a" #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:150 msgid "There are many feeds to try:" -msgstr "" +msgstr "Ci sono molti feed da provare:" #: src/view/screens/ProfileFeed.tsx:550 msgid "There was an an issue contacting the server, please check your internet connection and try again." @@ -4102,7 +4026,7 @@ msgstr "Si è verificato un problema durante il contatto con il tuo server" msgid "There was an issue fetching notifications. Tap here to try again." msgstr "Si è verificato un problema durante il recupero delle notifiche. Tocca qui per riprovare." -#: src/view/com/posts/Feed.tsx:263 +#: src/view/com/posts/Feed.tsx:265 msgid "There was an issue fetching posts. Tap here to try again." msgstr "Si è verificato un problema nel recupero dei post. Tocca qui per riprovare." @@ -4148,7 +4072,7 @@ msgstr "Si è verificato un problema imprevisto nell'applicazione. Per favore fa #: src/screens/Deactivated.tsx:106 msgid "There's been a rush of new users to Bluesky! We'll activate your account as soon as we can." -msgstr "" +msgstr "C'è stata un'ondata di nuovi utenti su Bluesky! Attiveremo il tuo account il prima possibile." #: src/view/com/auth/create/Step2.tsx:55 #~ msgid "There's something wrong with this number. Please choose your country and enter your full phone number!" @@ -4156,10 +4080,7 @@ msgstr "" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:138 msgid "These are popular accounts you might like:" -msgstr "" - -#~ msgid "This {0} has been labeled." -#~ msgstr "Este {0} ha sido etiquetado." +msgstr "Questi sono gli account popolari che potrebbero piacerti:" #: src/view/com/util/moderation/ScreenHider.tsx:88 msgid "This {screenDescription} has been flagged:" @@ -4183,7 +4104,7 @@ msgstr "Questo contenuto non è visualizzabile senza un account Bluesky." #: src/view/screens/Settings/ExportCarDialog.tsx:75 msgid "This feature is in beta. You can read more about repository exports in <0>this blogpost.</0>" -msgstr "" +msgstr "Questa funzionalità è in versione beta. Puoi leggere ulteriori informazioni sulle esportazioni dell' archivio in <0>questo post del blog.</0>" #: src/view/com/posts/FeedErrorMessage.tsx:114 msgid "This feed is currently receiving high traffic and is temporarily unavailable. Please try again later." @@ -4207,14 +4128,11 @@ msgstr "Queste informazioni non vengono condivise con altri utenti." msgid "This is important in case you ever need to change your email or reset your password." msgstr "Questo è importante nel caso in cui avessi bisogno di modificare la tua email o reimpostare la password." -#~ msgid "This is the service that keeps you online." -#~ msgstr "Aquest és el servei que et manté connectat." - #: src/view/com/modals/LinkWarning.tsx:58 msgid "This link is taking you to the following website:" msgstr "Questo link ti porta al seguente sito web:" -#: src/view/screens/ProfileList.tsx:834 +#: src/view/screens/ProfileList.tsx:839 msgid "This list is empty!" msgstr "La lista è vuota!" @@ -4236,21 +4154,17 @@ msgstr "Questo utente è incluso nell'elenco <0/> che hai bloccato." #: src/view/com/modals/ModerationDetails.tsx:74 msgid "This user is included in the <0/> list which you have muted." -msgstr "" - -#: src/view/com/modals/ModerationDetails.tsx:74 -#~ msgid "This user is included the <0/> list which you have muted." -#~ msgstr "Questo utente è incluso nell'elenco <0/> che hai silenziato." +msgstr "Questo utente è incluso nell'elenco <0/> che hai disattivato." #: src/view/com/modals/SelfLabel.tsx:137 msgid "This warning is only available for posts with media attached." msgstr "Questo avviso è disponibile solo per i post con contenuti multimediali allegati." -#: src/components/dialogs/MutedWords.tsx:236 +#: src/components/dialogs/MutedWords.tsx:285 msgid "This will delete {0} from your muted words. You can always add it back later." msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:237 +#: src/view/com/util/forms/PostDropdownBtn.tsx:282 msgid "This will hide this post from your feeds." msgstr "Questo nasconderà il post dai tuoi feeds." @@ -4263,11 +4177,11 @@ msgstr "Preferenze delle discussioni" msgid "Threaded Mode" msgstr "Modalità discussione" -#: src/Navigation.tsx:255 +#: src/Navigation.tsx:257 msgid "Threads Preferences" msgstr "Preferenze per le discussioni" -#: src/components/dialogs/MutedWords.tsx:95 +#: src/components/dialogs/MutedWords.tsx:113 msgid "Toggle between muted word options." msgstr "" @@ -4281,7 +4195,8 @@ msgstr "Trasformazioni" #: src/view/com/post-thread/PostThreadItem.tsx:685 #: src/view/com/post-thread/PostThreadItem.tsx:687 -#: src/view/com/util/forms/PostDropdownBtn.tsx:156 +#: src/view/com/util/forms/PostDropdownBtn.tsx:215 +#: src/view/com/util/forms/PostDropdownBtn.tsx:217 msgid "Translate" msgstr "Tradurre" @@ -4324,8 +4239,7 @@ msgstr "Sblocca" msgid "Unblock Account" msgstr "Sblocca il conto" -#: src/view/com/modals/Repost.tsx:42 -#: src/view/com/modals/Repost.tsx:55 +#: src/view/com/modals/Repost.tsx:42 src/view/com/modals/Repost.tsx:55 #: src/view/com/util/post-ctrls/RepostButton.tsx:60 #: src/view/com/util/post-ctrls/RepostButton.web.tsx:48 msgid "Undo repost" @@ -4345,16 +4259,15 @@ msgid "Unfortunately, you do not meet the requirements to create an account." msgstr "Sfortunatamente, non soddisfi i requisiti per creare un account." #: src/view/com/util/post-ctrls/PostCtrls.tsx:182 -#: src/view/com/util/post-ctrls/PostCtrls.tsx:216 msgid "Unlike" msgstr "Togli Mi piace" -#: src/components/TagMenu/index.tsx:253 +#: src/components/TagMenu/index.tsx:249 #: src/view/screens/ProfileList.tsx:597 msgid "Unmute" msgstr "Riattiva" -#: src/components/TagMenu/index.web.tsx:90 +#: src/components/TagMenu/index.web.tsx:104 msgid "Unmute {truncatedTag}" msgstr "" @@ -4362,11 +4275,16 @@ msgstr "" msgid "Unmute Account" msgstr "Riattiva questo account" -#: src/components/TagMenu/index.tsx:210 -msgid "Unmute all {tag} posts" +#: src/components/TagMenu/index.tsx:208 +msgid "Unmute all {displayTag} posts" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:202 +#: src/components/TagMenu/index.tsx:210 +#~ msgid "Unmute all {tag} posts" +#~ msgstr "" + +#: src/view/com/util/forms/PostDropdownBtn.tsx:251 +#: src/view/com/util/forms/PostDropdownBtn.tsx:256 msgid "Unmute thread" msgstr "Riattiva questa discussione" @@ -4421,10 +4339,6 @@ msgstr "Utilizza il mio browser predefinito" msgid "Use this to sign into the other app along with your handle." msgstr "Utilizza questo per accedere all'altra app insieme al tuo nome utente." -#: src/view/com/modals/ServerInput.tsx:105 -#~ msgid "Use your domain as your Bluesky client service provider" -#~ msgstr "Utilizza il tuo dominio come provider di servizi clienti Bluesky" - #: src/view/com/modals/InviteCodes.tsx:200 msgid "Used by:" msgstr "Usato da:" @@ -4448,36 +4362,36 @@ msgstr "Handle dell'utente" #: src/view/com/lists/ListCard.tsx:85 #: src/view/com/modals/UserAddRemoveLists.tsx:198 msgid "User list by {0}" -msgstr "Lista utenti di {0}" +msgstr "Lista di {0}" -#: src/view/screens/ProfileList.tsx:762 +#: src/view/screens/ProfileList.tsx:763 msgid "User list by <0/>" -msgstr "Lista utenti di<0/>" +msgstr "Lista di<0/>" #: src/view/com/lists/ListCard.tsx:83 #: src/view/com/modals/UserAddRemoveLists.tsx:196 -#: src/view/screens/ProfileList.tsx:760 +#: src/view/screens/ProfileList.tsx:761 msgid "User list by you" -msgstr "La tua lista utenti" +msgstr "La tua lista" #: src/view/com/modals/CreateOrEditList.tsx:196 msgid "User list created" -msgstr "Lista utenti creata" +msgstr "Lista creata" #: src/view/com/modals/CreateOrEditList.tsx:182 msgid "User list updated" -msgstr "Lista utenti aggiornata" +msgstr "Lista aggiornata" #: src/view/screens/Lists.tsx:58 msgid "User Lists" -msgstr "Lista utenti" +msgstr "Liste publiche" #: src/view/com/auth/login/LoginForm.tsx:177 #: src/view/com/auth/login/LoginForm.tsx:195 msgid "Username or email address" msgstr "Nome utente o indirizzo Email" -#: src/view/screens/ProfileList.tsx:796 +#: src/view/screens/ProfileList.tsx:797 msgid "Users" msgstr "Utenti" @@ -4516,7 +4430,7 @@ msgstr "Verifica la tua email" #: src/screens/Onboarding/index.tsx:42 msgid "Video Games" -msgstr "" +msgstr "Video Games" #: src/view/com/profile/ProfileHeader.tsx:662 msgid "View {0}'s avatar" @@ -4549,35 +4463,39 @@ msgstr "Avvisa" #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:134 msgid "We also think you'll like \"For You\" by Skygaze:" +msgstr "Pensiamo che ti piacerà anche \"Per Te\" di Skygaze:" + +#: src/screens/Hashtag.tsx:132 +msgid "We couldn't find any results for that hashtag." msgstr "" #: src/screens/Deactivated.tsx:133 msgid "We estimate {estimatedTime} until your account is ready." -msgstr "" +msgstr "Stimiamo {estimatedTime} prima che il tuo account sia pronto." #: src/screens/Onboarding/StepFinished.tsx:93 msgid "We hope you have a wonderful time. Remember, Bluesky is:" -msgstr "" +msgstr "Speriamo di darti dei momenti dei bei momenti. Ricorda, Bluesky è:" #: src/view/com/posts/DiscoverFallbackHeader.tsx:29 msgid "We ran out of posts from your follows. Here's the latest from <0/>." msgstr "Abbiamo esaurito i posts dei tuoi follower. Ecco le ultime novità da <0/>." -#: src/components/dialogs/MutedWords.tsx:161 +#: src/components/dialogs/MutedWords.tsx:204 msgid "We recommend avoiding common words that appear in many posts, since it can result in no posts being shown." msgstr "" #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:124 msgid "We recommend our \"Discover\" feed:" -msgstr "" +msgstr "Consigliamo il nostro feed \"Scopri\":" #: src/screens/Onboarding/StepInterests/index.tsx:133 msgid "We weren't able to connect. Please try again to continue setting up your account. If it continues to fail, you can skip this flow." -msgstr "" +msgstr "Non siamo riusciti a connetterci. Riprova per continuare a configurare il tuo account. Se il problema persiste, puoi ignorare questo flusso." #: src/screens/Deactivated.tsx:137 msgid "We will let you know when your account is ready." -msgstr "" +msgstr "Ti faremo sapere quando il tuo account sarà pronto." #: src/view/com/modals/AppealLabel.tsx:48 msgid "We'll look into your appeal promptly." @@ -4585,7 +4503,7 @@ msgstr "Esamineremo il tuo ricorso al più presto." #: src/screens/Onboarding/StepInterests/index.tsx:138 msgid "We'll use this to help customize your experience." -msgstr "" +msgstr "Lo useremo per personalizzare la tua esperienza." #: src/view/com/auth/create/CreateAccount.tsx:134 msgid "We're so excited to have you join us!" @@ -4595,7 +4513,7 @@ msgstr "Siamo felici che tu ti unisca a noi!" msgid "We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @{handleOrDid}." msgstr "Siamo spiacenti, ma non siamo riusciti a risolvere questa lista. Se il problema persiste, contatta il creatore della lista, @{handleOrDid}." -#: src/components/dialogs/MutedWords.tsx:182 +#: src/components/dialogs/MutedWords.tsx:230 msgid "We're sorry, but we weren't able to load your muted words at this time. Please try again." msgstr "" @@ -4603,6 +4521,7 @@ msgstr "" msgid "We're sorry, but your search could not be completed. Please try again in a few minutes." msgstr "Siamo spiacenti, ma non è stato possibile completare la ricerca. Riprova tra qualche minuto." +#: src/components/Lists.tsx:211 #: src/view/screens/NotFound.tsx:48 msgid "We're sorry! We can't find the page you were looking for." msgstr "Ci dispiace! Non riusciamo a trovare la pagina che stavi cercando." @@ -4613,7 +4532,7 @@ msgstr "Ti diamo il benvenuto a <0>Bluesky</0>" #: src/screens/Onboarding/StepInterests/index.tsx:130 msgid "What are your interests?" -msgstr "" +msgstr "Quali sono i tuoi interessi?" #: src/view/com/modals/report/Modal.tsx:169 msgid "What is the issue with this {collectionName}?" @@ -4655,7 +4574,7 @@ msgstr "Scrivi la tua risposta" #: src/screens/Onboarding/index.tsx:28 msgid "Writers" -msgstr "" +msgstr "Scrittori" #: src/view/com/auth/create/Step2.tsx:263 #~ msgid "XXXXXX" @@ -4673,19 +4592,16 @@ msgstr "Si" #: src/screens/Deactivated.tsx:130 msgid "You are in line." -msgstr "" +msgstr "Sei nella fila." #: src/view/com/posts/FollowingEmptyState.tsx:67 #: src/view/com/posts/FollowingEndOfFeed.tsx:68 msgid "You can also discover new Custom Feeds to follow." msgstr "Puoi anche scoprire nuovi feed personalizzati da seguire." -#~ msgid "You can change hosting providers at any time." -#~ msgstr "Pots canviar el teu proveïdor d'allotjament quan vulguis." - #: src/screens/Onboarding/StepFollowingFeed.tsx:142 msgid "You can change these settings later." -msgstr "" +msgstr "Potrai modificare queste impostazioni in seguito." #: src/view/com/auth/login/Login.tsx:158 #: src/view/com/auth/login/PasswordUpdatedForm.tsx:31 @@ -4721,18 +4637,17 @@ msgstr "Hai bloccato questo utente. Non è possibile visualizzare il contenuto." #: src/view/com/modals/ChangePassword.tsx:87 #: src/view/com/modals/ChangePassword.tsx:121 msgid "You have entered an invalid code. It should look like XXXXX-XXXXX." -msgstr "" +msgstr "Hai inserito un codice non valido. Dovrebbe apparire come XXXX-XXXXXX." #: src/view/com/modals/ModerationDetails.tsx:87 msgid "You have muted this user." -msgstr "Hai silenziato questo utente." +msgstr "Hai disattivato questo utente." #: src/view/com/feeds/ProfileFeedgens.tsx:136 msgid "You have no feeds." msgstr "Non hai feeds." -#: src/view/com/lists/MyLists.tsx:89 -#: src/view/com/lists/ProfileLists.tsx:140 +#: src/view/com/lists/MyLists.tsx:89 src/view/com/lists/ProfileLists.tsx:140 msgid "You have no lists." msgstr "Non hai liste." @@ -4748,7 +4663,7 @@ msgstr "Non hai ancora creato alcuna password per l'app. Puoi crearne uno premen msgid "You have not muted any accounts yet. To mute an account, go to their profile and selected \"Mute account\" from the menu on their account." msgstr "Non hai ancora disattivato alcun account. Per disattivare un account, vai al suo profilo e seleziona \"Disattiva account\" dal menu del account." -#: src/components/dialogs/MutedWords.tsx:202 +#: src/components/dialogs/MutedWords.tsx:250 msgid "You haven't muted any words or tags yet" msgstr "" @@ -4758,13 +4673,13 @@ msgstr "Devi avere almeno 18 anni per abilitare i contenuti per adulti." #: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:103 msgid "You must be 18 years or older to enable adult content" -msgstr "" +msgstr "Devi avere almeno 18 anni per abilitare i contenuti per adulti" -#: src/view/com/util/forms/PostDropdownBtn.tsx:129 +#: src/view/com/util/forms/PostDropdownBtn.tsx:147 msgid "You will no longer receive notifications for this thread" msgstr "Non riceverai più notifiche per questo filo di discussione" -#: src/view/com/util/forms/PostDropdownBtn.tsx:132 +#: src/view/com/util/forms/PostDropdownBtn.tsx:150 msgid "You will now receive notifications for this thread" msgstr "Adesso riceverai le notifiche per questa discussione" @@ -4774,23 +4689,22 @@ msgstr "Riceverai un'email con un \"codice di reset\". Inserisci il codice qui, #: src/screens/Onboarding/StepModeration/index.tsx:72 msgid "You're in control" -msgstr "" +msgstr "Sei in controllo" -#: src/screens/Deactivated.tsx:87 -#: src/screens/Deactivated.tsx:88 +#: src/screens/Deactivated.tsx:87 src/screens/Deactivated.tsx:88 #: src/screens/Deactivated.tsx:103 msgid "You're in line" -msgstr "" +msgstr "Sei in fila" #: src/screens/Onboarding/StepFinished.tsx:90 msgid "You're ready to go!" -msgstr "" +msgstr "Sei pronto per iniziare!" #: src/view/com/posts/FollowingEndOfFeed.tsx:48 msgid "You've reached the end of your feed! Find some more accounts to follow." msgstr "Hai raggiunto la fine del tuo feed! Trova altri account da seguire." -#: src/view/com/auth/create/Step1.tsx:74 +#: src/view/com/auth/create/Step1.tsx:67 msgid "Your account" msgstr "Il tuo account" @@ -4800,9 +4714,9 @@ msgstr "Il tuo account è stato eliminato" #: src/view/screens/Settings/ExportCarDialog.tsx:47 msgid "Your account repository, containing all public data records, can be downloaded as a \"CAR\" file. This file does not include media embeds, such as images, or your private data, which must be fetched separately." -msgstr "" +msgstr "L'archivio del tuo account, che contiene tutti i record di dati pubblici, può essere scaricato come file \"CAR\". Questo file non include elementi multimediali incorporati, come immagini o dati privati, che devono essere recuperati separatamente." -#: src/view/com/auth/create/Step1.tsx:238 +#: src/view/com/auth/create/Step1.tsx:215 msgid "Your birth date" msgstr "La tua data di nascita" @@ -4812,7 +4726,7 @@ msgstr "La tua scelta verrà salvata, ma potrà essere modificata successivament #: src/screens/Onboarding/StepFollowingFeed.tsx:61 msgid "Your default feed is \"Following\"" -msgstr "" +msgstr "Il tuo feed predefinito è \"Following\"" #: src/view/com/auth/create/state.ts:110 #: src/view/com/auth/login/ForgotPasswordForm.tsx:70 @@ -4821,8 +4735,8 @@ msgid "Your email appears to be invalid." msgstr "Your email appears to be invalid." #: src/view/com/modals/Waitlist.tsx:109 -msgid "Your email has been saved! We'll be in touch soon." -msgstr "La tua email è stata salvata! Ci metteremo in contatto al più presto." +#~ msgid "Your email has been saved! We'll be in touch soon." +#~ msgstr "La tua email è stata salvata! Ci metteremo in contatto al più presto." #: src/view/com/modals/ChangeEmail.tsx:125 msgid "Your email has been updated but not verified. As a next step, please verify your new email." @@ -4852,13 +4766,13 @@ msgstr "Il tuo nome di utente completo sarà <0>@{0}</0>" #~ msgid "Your invite codes are hidden when logged in using an App Password" #~ msgstr "I tuoi codici di invito vengono celati quando accedi utilizzando una password per l'app" -#: src/components/dialogs/MutedWords.tsx:173 +#: src/components/dialogs/MutedWords.tsx:221 msgid "Your muted words" msgstr "" #: src/view/com/modals/ChangePassword.tsx:155 msgid "Your password has been changed successfully!" -msgstr "" +msgstr "La tua password è stata modificata correttamente!" #: src/view/com/composer/Composer.tsx:274 msgid "Your post has been published" @@ -4882,3 +4796,153 @@ msgstr "La tua risposta è stata pubblicata" #: src/view/com/auth/create/Step2.tsx:65 msgid "Your user handle" msgstr "Il tuo handle utente" + +#~ msgid "{0, plural, one {# invite code available} other {# invite codes available}}" +#~ msgstr "{0, plural, one {# codice d'invito disponibile} other {# codici d'inviti disponibili}}" + +#~ msgid "{0}" +#~ msgstr "{0}" + +#~ msgid "{0} {purposeLabel} List" +#~ msgstr "Lista {purposeLabel} {0}" + +#~ msgid "{invitesAvailable, plural, one {Invite codes: # available} other {Invite codes: # available}}" +#~ msgstr "{invitesAvailable, plural, one {Codici d'invito: # available} other {Codici d'invito: # available}}" + +#~ msgid "{invitesAvailable} invite code available" +#~ msgstr "{invitesAvailable} codice d'invito disponibile" + +#~ msgid "{invitesAvailable} invite codes available" +#~ msgstr "{invitesAvailable} codici d'invito disponibili" + +#~ msgid "{message}" +#~ msgstr "{message}" + +#~ msgid "App passwords" +#~ msgstr "Passwords dell'app" + +#~ msgid "Appeal Decision" +#~ msgstr "Decisión de apelación" + +#~ msgid "Bluesky.Social" +#~ msgstr "Bluesky.Social" + +#~ msgid "Button disabled. Input custom domain to proceed." +#~ msgstr "Pulsante disabilitato. Inserisci il dominio personalizzato per procedere." + +#~ msgid "Cancel add image alt text" +#~ msgstr "Cancel·la afegir text a la imatge" + +#~ msgid "Change" +#~ msgstr "Cambia" + +#~ msgid "Danger Zone" +#~ msgstr "Zona di Pericolo" + +#~ msgid "Delete my account…" +#~ msgstr "Cancella il mio account…" + +#~ msgid "Dev Server" +#~ msgstr "Server di sviluppo" + +#~ msgid "Developer Tools" +#~ msgstr "Strumenti per sviluppatori" + +#~ msgid "Discover new feeds" +#~ msgstr "Scopri nuovi feeds" + +#~ msgid "Enter the address of your provider:" +#~ msgstr "Inserisci l'indirizzo del tuo provider:" + +#~ msgid "following" +#~ msgstr "following" + +#~ msgid "Hosting provider address" +#~ msgstr "Indirizzo del fornitore di hosting" + +#~ msgid "Invite" +#~ msgstr "Invita" + +#~ msgid "Invite codes: {invitesAvailable} available" +#~ msgstr "Codici di invito: {invitesAvailable} disponibili" + +#~ msgid "liked your custom feed{0}" +#~ msgstr "piace il feed personalizzato{0}" + +#~ msgid "Local dev server" +#~ msgstr "Server di sviluppo locale" + +#~ msgid "Looks like this feed is only available to users with a Bluesky account. Please sign up or sign in to view this feed!" +#~ msgstr "Sembra che questo feed sia disponibile solo per gli utenti con un account Bluesky. Per favore registrati o accedi per visualizzare questo feed!" + +#~ msgid "Message from server" +#~ msgstr "Messaggio dal server" + +#~ msgid "New Post" +#~ msgstr "Nuovo Post" + +#~ msgid "Opens invite code list" +#~ msgstr "Apre la lista dei codici di invito" + +#~ msgid "Other service" +#~ msgstr "Altro servizio" + +#~ msgid "Please tell us why you think this decision was incorrect." +#~ msgstr "Per favore spiegaci perché ritieni che questa decisione sia stata sbagliata." + +#~ msgid "Post" +#~ msgstr "Post" + +#~ msgid "Quote Post" +#~ msgstr "Cita il post" + +#~ msgid "Reposted by" +#~ msgstr "Repost di" + +#~ msgid "Reposted by {0})" +#~ msgstr "Repost di {0})" + +#~ msgid "Select Bluesky Social" +#~ msgstr "Seleziona Bluesky Social" + +#~ msgid "Send Email" +#~ msgstr "Envia Email" + +#~ msgid "Something went wrong and we're not sure what." +#~ msgstr "Qualcosa è andato storto ma non siamo sicuri di cosa." + +#~ msgid "Staging" +#~ msgstr "Allestimento" + +#~ msgid "Swipe up to see more" +#~ msgstr "Scorri verso l'alto per vedere di più" + +#~ msgid "The support form has been moved. If you need help, please<0/> or visit {HELP_DESK_URL} to get in touch with us." +#~ msgstr "Il modulo di supporto è stato spostato. Se hai bisogno di aiuto, <0/> o visita {HELP_DESK_URL} per metterti in contatto con noi." + +#~ msgid "This {0} has been labeled." +#~ msgstr "Questo {0} è stato etichettato." + +#~ msgid "This is the service that keeps you online." +#~ msgstr "Questo è il servizio che ti mantiene online." + +#~ msgid "This user is included the <0/> list which you have muted." +#~ msgstr "Questo utente è incluso nella lista <0/> che hai silenziato." + +#~ msgid "Try again" +#~ msgstr "Provalo di nuovo" + +#~ msgid "Use your domain as your Bluesky client service provider" +#~ msgstr "Utilizza il tuo dominio come provider di servizi clienti Bluesky" + +#~ msgid "What's next?" +#~ msgstr "Qual è il prossimo?" + +#~ msgid "You can change hosting providers at any time." +#~ msgstr "Puoi cambiare provider di hosting in qualsiasi momento." + +#~ msgid "Your hosting provider" +#~ msgstr "Il tuo fornitore di hosting" + +#~ msgid "Your invite codes are hidden when logged in using an App Password" +#~ msgstr "I tuoi codici di invito vengono celati quando accedi utilizzando una password per l'app" diff --git a/src/locale/locales/ja/messages.po b/src/locale/locales/ja/messages.po index 21f2e5e0f..6c50bc9f2 100644 --- a/src/locale/locales/ja/messages.po +++ b/src/locale/locales/ja/messages.po @@ -92,12 +92,12 @@ msgstr "ã“ã®{0}ã«ã‚³ãƒ³ãƒ†ãƒ³ãƒ„ã®è¦å‘ŠãŒé©ç”¨ã•れã¦ã„ã¾ã™ã€‚" msgid "A new version of the app is available. Please update to continue using the app." msgstr "æ–°ã—ã„ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã®ã‚¢ãƒ—リãŒåˆ©ç”¨å¯èƒ½ã§ã™ã€‚継続ã—ã¦ä½¿ç”¨ã™ã‚‹ãŸã‚ã«ã¯ã‚¢ãƒƒãƒ—デートã—ã¦ãã ã•ã„。" -#: src/view/com/util/ViewHeader.tsx:83 +#: src/view/com/util/ViewHeader.tsx:89 #: src/view/screens/Search/Search.tsx:647 msgid "Access navigation links and settings" msgstr "ナビゲーションリンクã¨è¨å®šã«ã‚¢ã‚¯ã‚»ã‚¹" -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:51 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:52 msgid "Access profile and other navigation links" msgstr "プãƒãƒ•ィールã¨ä»–ã®ãƒŠãƒ“ゲーションリンクã«ã‚¢ã‚¯ã‚»ã‚¹" @@ -144,11 +144,11 @@ msgstr "アカウントã®ãƒ–ãƒãƒƒã‚¯ã‚’解除ã—ã¾ã—ãŸ" msgid "Account unmuted" msgstr "アカウントã®ãƒŸãƒ¥ãƒ¼ãƒˆã‚’解除ã—ã¾ã—ãŸ" -#: src/components/dialogs/MutedWords.tsx:147 +#: src/components/dialogs/MutedWords.tsx:165 #: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:150 #: src/view/com/modals/ListAddRemoveUsers.tsx:264 #: src/view/com/modals/UserAddRemoveLists.tsx:219 -#: src/view/screens/ProfileList.tsx:812 +#: src/view/screens/ProfileList.tsx:813 msgid "Add" msgstr "è¿½åŠ " @@ -156,7 +156,7 @@ msgstr "è¿½åŠ " msgid "Add a content warning" msgstr "コンテンツã®è¦å‘Šã‚’è¿½åŠ " -#: src/view/screens/ProfileList.tsx:802 +#: src/view/screens/ProfileList.tsx:803 msgid "Add a user to this list" msgstr "リストã«ãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚’è¿½åŠ " @@ -194,11 +194,11 @@ msgstr "ãƒªãƒ³ã‚¯ã‚«ãƒ¼ãƒ‰ã‚’è¿½åŠ " msgid "Add link card:" msgstr "ãƒªãƒ³ã‚¯ã‚«ãƒ¼ãƒ‰ã‚’è¿½åŠ ï¼š" -#: src/components/dialogs/MutedWords.tsx:140 +#: src/components/dialogs/MutedWords.tsx:158 msgid "Add mute word for configured settings" msgstr "" -#: src/components/dialogs/MutedWords.tsx:74 +#: src/components/dialogs/MutedWords.tsx:87 msgid "Add muted words and tags" msgstr "" @@ -286,7 +286,7 @@ msgstr "以å‰ã®ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹{0}ã«ãƒ¡ãƒ¼ãƒ«ãŒé€ä¿¡ã•れã¾ã—ãŸã€‚ msgid "An issue occurred, please try again." msgstr "å•題ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ãŠè©¦ã—ãã ã•ã„。" -#: src/view/com/notifications/FeedItem.tsx:236 +#: src/view/com/notifications/FeedItem.tsx:237 #: src/view/com/threadgate/WhoCanReply.tsx:178 msgid "and" msgstr "ãŠã‚ˆã³" @@ -319,13 +319,14 @@ msgstr "アプリパスワードã®è¨å®š" #~ msgid "App passwords" #~ msgstr "アプリパスワード" -#: src/Navigation.tsx:237 +#: src/Navigation.tsx:239 #: src/view/screens/AppPasswords.tsx:187 #: src/view/screens/Settings/index.tsx:684 msgid "App Passwords" msgstr "アプリパスワード" -#: src/view/com/util/forms/PostDropdownBtn.tsx:295 +#: src/view/com/util/forms/PostDropdownBtn.tsx:337 +#: src/view/com/util/forms/PostDropdownBtn.tsx:346 msgid "Appeal content warning" msgstr "コンテンツã®è¦å‘Šã«ç•°è°ã‚’申ã—ç«‹ã¦ã‚‹" @@ -357,12 +358,12 @@ msgstr "アプリパスワード「{name}ã€ã‚’本当ã«å‰Šé™¤ã—ã¾ã™ã‹ï¼Ÿ" msgid "Are you sure you'd like to discard this draft?" msgstr "本当ã«ã“ã®ä¸‹æ›¸ãã‚’ç ´æ£„ã—ã¾ã™ã‹ï¼Ÿ" -#: src/components/dialogs/MutedWords.tsx:233 +#: src/components/dialogs/MutedWords.tsx:282 #: src/view/screens/ProfileList.tsx:365 msgid "Are you sure?" msgstr "本当ã«ã‚ˆã‚ã—ã„ã§ã™ã‹ï¼Ÿ" -#: src/view/com/util/forms/PostDropdownBtn.tsx:278 +#: src/view/com/util/forms/PostDropdownBtn.tsx:322 msgid "Are you sure? This cannot be undone." msgstr "本当ã«ã‚ˆã‚ã—ã„ã§ã™ã‹ï¼Ÿã“れã¯å…ƒã«æˆ»ã›ã¾ã›ã‚“。" @@ -388,7 +389,7 @@ msgstr "芸術的ã¾ãŸã¯æ€§çš„ã§ã¯ãªã„ヌード。" #: src/view/com/post-thread/PostThread.tsx:522 #: src/view/com/post-thread/PostThread.tsx:530 #: src/view/com/profile/ProfileHeader.tsx:649 -#: src/view/com/util/ViewHeader.tsx:81 +#: src/view/com/util/ViewHeader.tsx:87 msgid "Back" msgstr "戻る" @@ -405,7 +406,7 @@ msgstr "「{interestsText}ã€ã¸ã®èˆˆå‘³ã«åŸºã¥ã„ãŸãŠã™ã™ã‚ã§ã™ã€‚" msgid "Basics" msgstr "基本" -#: src/view/com/auth/create/Step1.tsx:250 +#: src/view/com/auth/create/Step1.tsx:227 #: src/view/com/modals/BirthDateSettings.tsx:73 msgid "Birthday" msgstr "誕生日" @@ -444,7 +445,7 @@ msgstr "ブãƒãƒƒã‚¯ã•れã¦ã„ã¾ã™" msgid "Blocked accounts" msgstr "ブãƒãƒƒã‚¯ä¸ã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆ" -#: src/Navigation.tsx:130 +#: src/Navigation.tsx:132 #: src/view/screens/ModerationBlockedAccounts.tsx:107 msgid "Blocked Accounts" msgstr "ブãƒãƒƒã‚¯ä¸ã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆ" @@ -496,8 +497,8 @@ msgid "Bluesky is public." msgstr "Blueskyã¯ãƒ‘ブリックã§ã™ã€‚" #: src/view/com/modals/Waitlist.tsx:70 -msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon." -msgstr "Blueskyã¯ã‚ˆã‚Šå¥å…¨ãªã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ãƒ¼ã‚’構築ã™ã‚‹ãŸã‚ã«æ‹›å¾…状を使用ã—ã¾ã™ã€‚æ‹›å¾…çŠ¶ã‚’ãŠæŒã¡ã§ãªã„å ´åˆã€Waitlistã«ãŠç”³ã—è¾¼ã¿ã„ãŸã ãã¨æ‹›å¾…状をãŠé€ã‚Šã—ã¾ã™ã€‚" +#~ msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon." +#~ msgstr "Blueskyã¯ã‚ˆã‚Šå¥å…¨ãªã‚³ãƒŸãƒ¥ãƒ‹ãƒ†ã‚£ãƒ¼ã‚’構築ã™ã‚‹ãŸã‚ã«æ‹›å¾…状を使用ã—ã¾ã™ã€‚æ‹›å¾…çŠ¶ã‚’ãŠæŒã¡ã§ãªã„å ´åˆã€Waitlistã«ãŠç”³ã—è¾¼ã¿ã„ãŸã ãã¨æ‹›å¾…状をãŠé€ã‚Šã—ã¾ã™ã€‚" #: src/view/screens/Moderation.tsx:245 msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private." @@ -550,7 +551,7 @@ msgstr "カメラ" msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must be at least 4 characters long, but no more than 32 characters long." msgstr "英数å—ã€ã‚¹ãƒšãƒ¼ã‚¹ã€ãƒã‚¤ãƒ•ンã€ã‚¢ãƒ³ãƒ€ãƒ¼ã‚¹ã‚³ã‚¢ã®ã¿ãŒä½¿ç”¨å¯èƒ½ã§ã™ã€‚é•·ã•ã¯4æ–‡å—以上32æ–‡å—以下ã§ã‚ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚" -#: src/components/Prompt.tsx:91 +#: src/components/Prompt.tsx:101 #: src/view/com/composer/Composer.tsx:307 #: src/view/com/composer/Composer.tsx:312 #: src/view/com/modals/ChangeEmail.tsx:218 @@ -565,7 +566,6 @@ msgstr "英数å—ã€ã‚¹ãƒšãƒ¼ã‚¹ã€ãƒã‚¤ãƒ•ンã€ã‚¢ãƒ³ãƒ€ãƒ¼ã‚¹ã‚³ã‚¢ã®ã¿ãŒ #: src/view/com/modals/Repost.tsx:87 #: src/view/com/modals/VerifyEmail.tsx:247 #: src/view/com/modals/VerifyEmail.tsx:253 -#: src/view/com/modals/Waitlist.tsx:142 #: src/view/screens/Search/Search.tsx:716 #: src/view/shell/desktop/Search.tsx:238 msgid "Cancel" @@ -611,8 +611,8 @@ msgid "Cancel search" msgstr "検索をã‚ャンセル" #: src/view/com/modals/Waitlist.tsx:136 -msgid "Cancel waitlist signup" -msgstr "Waitlistã®ç™»éŒ²ã‚’ã‚ャンセル" +#~ msgid "Cancel waitlist signup" +#~ msgstr "Waitlistã®ç™»éŒ²ã‚’ã‚ャンセル" #: src/view/screens/Settings/index.tsx:334 msgctxt "action" @@ -702,7 +702,7 @@ msgstr "カスタムフィードを使用ã—ã¦ã‚ãªãŸã®ä½“験を強化ã™ã‚‹ msgid "Choose your main feeds" msgstr "メインã®ãƒ•ã‚£ãƒ¼ãƒ‰ã‚’é¸æŠž" -#: src/view/com/auth/create/Step1.tsx:219 +#: src/view/com/auth/create/Step1.tsx:196 msgid "Choose your password" msgstr "パスワードを入力" @@ -733,11 +733,14 @@ msgstr "検索クエリをクリア" msgid "click here" msgstr "ã“ã¡ã‚‰ã‚’クリック" -#: src/components/RichText.tsx:189 -#: src/components/TagMenu/index.web.tsx:125 +#: src/components/TagMenu/index.web.tsx:138 msgid "Click here to open tag menu for {tag}" msgstr "" +#: src/components/RichText.tsx:191 +msgid "Click here to open tag menu for #{tag}" +msgstr "" + #: src/screens/Onboarding/index.tsx:35 msgid "Climate" msgstr "気象" @@ -747,8 +750,8 @@ msgstr "気象" msgid "Close" msgstr "é–‰ã˜ã‚‹" -#: src/components/Dialog/index.web.tsx:80 -#: src/components/Dialog/index.web.tsx:194 +#: src/components/Dialog/index.web.tsx:84 +#: src/components/Dialog/index.web.tsx:198 msgid "Close active dialog" msgstr "アクティブãªãƒ€ã‚¤ã‚¢ãƒã‚°ã‚’é–‰ã˜ã‚‹" @@ -772,7 +775,7 @@ msgstr "ç”»åƒãƒ“ューアを閉ã˜ã‚‹" msgid "Close navigation footer" msgstr "ナビゲーションフッターを閉ã˜ã‚‹" -#: src/components/TagMenu/index.tsx:266 +#: src/components/TagMenu/index.tsx:262 msgid "Close this dialog" msgstr "" @@ -792,7 +795,7 @@ msgstr "投稿ã®ç·¨é›†ç”»é¢ã‚’é–‰ã˜ã€ä¸‹æ›¸ãを削除ã™ã‚‹" msgid "Closes viewer for header image" msgstr "ヘッダー画åƒã®ãƒ“ューワーを閉ã˜ã‚‹" -#: src/view/com/notifications/FeedItem.tsx:317 +#: src/view/com/notifications/FeedItem.tsx:318 msgid "Collapses list of users for a given notification" msgstr "指定ã—ãŸé€šçŸ¥ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ãƒªã‚¹ãƒˆã‚’折りãŸãŸã‚€" @@ -804,7 +807,7 @@ msgstr "コメディー" msgid "Comics" msgstr "漫画" -#: src/Navigation.tsx:227 +#: src/Navigation.tsx:229 #: src/view/screens/CommunityGuidelines.tsx:32 msgid "Community Guidelines" msgstr "コミュニティーガイドライン" @@ -829,7 +832,7 @@ msgstr "返信を作æˆ" msgid "Configure content filtering setting for category: {0}" msgstr "ã“ã®ã‚«ãƒ†ã‚´ãƒªã®ã‚³ãƒ³ãƒ†ãƒ³ãƒ„フィルタリングをè¨å®šï¼š {0}" -#: src/components/Prompt.tsx:113 +#: src/components/Prompt.tsx:124 #: src/view/com/modals/AppealLabel.tsx:98 #: src/view/com/modals/SelfLabel.tsx:154 #: src/view/com/modals/VerifyEmail.tsx:231 @@ -869,8 +872,8 @@ msgid "Confirmation code" msgstr "確èªã‚³ãƒ¼ãƒ‰" #: src/view/com/modals/Waitlist.tsx:120 -msgid "Confirms signing up {email} to the waitlist" -msgstr "{email}ã®Waitlistã¸ã®ç™»éŒ²ã‚’確èª" +#~ msgid "Confirms signing up {email} to the waitlist" +#~ msgstr "{email}ã®Waitlistã¸ã®ç™»éŒ²ã‚’確èª" #: src/view/com/auth/create/CreateAccount.tsx:193 #: src/view/com/auth/login/LoginForm.tsx:278 @@ -947,7 +950,7 @@ msgstr "ビルドãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’クリップボードã«ã‚³ãƒ”ーã—ã¾ã—㟠#: src/view/com/modals/AddAppPasswords.tsx:76 #: src/view/com/modals/InviteCodes.tsx:152 -#: src/view/com/util/forms/PostDropdownBtn.tsx:143 +#: src/view/com/util/forms/PostDropdownBtn.tsx:161 msgid "Copied to clipboard" msgstr "クリップボードã«ã‚³ãƒ”ーã—ã¾ã—ãŸ" @@ -963,7 +966,8 @@ msgstr "コピー" msgid "Copy link to list" msgstr "リストã¸ã®ãƒªãƒ³ã‚¯ã‚’コピー" -#: src/view/com/util/forms/PostDropdownBtn.tsx:184 +#: src/view/com/util/forms/PostDropdownBtn.tsx:231 +#: src/view/com/util/forms/PostDropdownBtn.tsx:237 msgid "Copy link to post" msgstr "投稿ã¸ã®ãƒªãƒ³ã‚¯ã‚’コピー" @@ -971,11 +975,12 @@ msgstr "投稿ã¸ã®ãƒªãƒ³ã‚¯ã‚’コピー" msgid "Copy link to profile" msgstr "プãƒãƒ•ィールã¸ã®ãƒªãƒ³ã‚¯ã‚’コピー" -#: src/view/com/util/forms/PostDropdownBtn.tsx:170 +#: src/view/com/util/forms/PostDropdownBtn.tsx:223 +#: src/view/com/util/forms/PostDropdownBtn.tsx:225 msgid "Copy post text" msgstr "投稿ã®ãƒ†ã‚ストをコピー" -#: src/Navigation.tsx:232 +#: src/Navigation.tsx:234 #: src/view/screens/CopyrightPolicy.tsx:29 msgid "Copyright Policy" msgstr "著作権ãƒãƒªã‚·ãƒ¼" @@ -984,7 +989,7 @@ msgstr "著作権ãƒãƒªã‚·ãƒ¼" msgid "Could not load feed" msgstr "フィードã®ãƒãƒ¼ãƒ‰ã«å¤±æ•—ã—ã¾ã—ãŸ" -#: src/view/screens/ProfileList.tsx:888 +#: src/view/screens/ProfileList.tsx:893 msgid "Could not load list" msgstr "リストã®ãƒãƒ¼ãƒ‰ã«å¤±æ•—ã—ã¾ã—ãŸ" @@ -1108,11 +1113,12 @@ msgstr "マイアカウントを削除" msgid "Delete My Account…" msgstr "マイアカウントを削除…" -#: src/view/com/util/forms/PostDropdownBtn.tsx:273 +#: src/view/com/util/forms/PostDropdownBtn.tsx:317 +#: src/view/com/util/forms/PostDropdownBtn.tsx:326 msgid "Delete post" msgstr "投稿を削除" -#: src/view/com/util/forms/PostDropdownBtn.tsx:277 +#: src/view/com/util/forms/PostDropdownBtn.tsx:321 msgid "Delete this post?" msgstr "ã“ã®æŠ•ç¨¿ã‚’å‰Šé™¤ã—ã¾ã™ã‹ï¼Ÿ" @@ -1185,8 +1191,8 @@ msgid "Domain verified!" msgstr "ドメインを確èªã—ã¾ã—ãŸï¼" #: src/view/com/auth/create/Step1.tsx:170 -msgid "Don't have an invite code?" -msgstr "æ‹›å¾…ã‚³ãƒ¼ãƒ‰ã‚’ãŠæŒã¡ã§ãªã„å ´åˆ" +#~ msgid "Don't have an invite code?" +#~ msgstr "æ‹›å¾…ã‚³ãƒ¼ãƒ‰ã‚’ãŠæŒã¡ã§ãªã„å ´åˆ" #: src/view/com/auth/onboarding/RecommendedFollows.tsx:86 #: src/view/com/modals/EditImage.tsx:333 @@ -1288,7 +1294,7 @@ msgstr "リストã®è©³ç´°ã‚’編集" msgid "Edit Moderation List" msgstr "モデレーションリストを編集" -#: src/Navigation.tsx:242 +#: src/Navigation.tsx:244 #: src/view/screens/Feeds.tsx:434 #: src/view/screens/SavedFeeds.tsx:84 msgid "Edit My Feeds" @@ -1306,7 +1312,7 @@ msgstr "プãƒãƒ•ィールを編集" msgid "Edit Profile" msgstr "プãƒãƒ•ィールを編集" -#: src/view/com/home/HomeHeaderLayout.web.tsx:59 +#: src/view/com/home/HomeHeaderLayout.web.tsx:62 #: src/view/screens/Feeds.tsx:355 msgid "Edit Saved Feeds" msgstr "ä¿å˜ã•れãŸãƒ•ィードを編集" @@ -1327,14 +1333,13 @@ msgstr "ã‚ãªãŸã®ãƒ—ãƒãƒ•ィールã®èª¬æ˜Žã‚’編集ã—ã¾ã™" msgid "Education" msgstr "教育" -#: src/view/com/auth/create/Step1.tsx:199 +#: src/view/com/auth/create/Step1.tsx:176 #: src/view/com/auth/login/ForgotPasswordForm.tsx:156 #: src/view/com/modals/ChangeEmail.tsx:141 -#: src/view/com/modals/Waitlist.tsx:88 msgid "Email" msgstr "メールアドレス" -#: src/view/com/auth/create/Step1.tsx:190 +#: src/view/com/auth/create/Step1.tsx:167 #: src/view/com/auth/login/ForgotPasswordForm.tsx:147 msgid "Email address" msgstr "メールアドレス" @@ -1389,8 +1394,8 @@ msgstr "フィードã®çµ‚ã‚り" msgid "Enter a name for this App Password" msgstr "ã“ã®ã‚¢ãƒ—リパスワードã®åå‰ã‚’入力" -#: src/components/dialogs/MutedWords.tsx:87 -#: src/components/dialogs/MutedWords.tsx:88 +#: src/components/dialogs/MutedWords.tsx:100 +#: src/components/dialogs/MutedWords.tsx:101 msgid "Enter a word or tag" msgstr "" @@ -1414,16 +1419,16 @@ msgstr "使用ã™ã‚‹ãƒ‰ãƒ¡ã‚¤ãƒ³ã‚’入力ã—ã¦ãã ã•ã„" msgid "Enter the email you used to create your account. We'll send you a \"reset code\" so you can set a new password." msgstr "アカウントã®ä½œæˆã«ä½¿ç”¨ã—ãŸãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’入力ã—ã¾ã™ã€‚æ–°ã—ã„パスワードをè¨å®šã§ãるよã†ã«ã€ã€Œãƒªã‚»ãƒƒãƒˆã‚³ãƒ¼ãƒ‰ã€ã‚’ãŠé€ã‚Šã—ã¾ã™ã€‚" -#: src/view/com/auth/create/Step1.tsx:251 +#: src/view/com/auth/create/Step1.tsx:228 #: src/view/com/modals/BirthDateSettings.tsx:74 msgid "Enter your birth date" msgstr "誕生日を入力ã—ã¦ãã ã•ã„" #: src/view/com/modals/Waitlist.tsx:78 -msgid "Enter your email" -msgstr "メールアドレスを入力ã—ã¦ãã ã•ã„" +#~ msgid "Enter your email" +#~ msgstr "メールアドレスを入力ã—ã¦ãã ã•ã„" -#: src/view/com/auth/create/Step1.tsx:195 +#: src/view/com/auth/create/Step1.tsx:172 msgid "Enter your email address" msgstr "メールアドレスを入力ã—ã¦ãã ã•ã„" @@ -1469,8 +1474,8 @@ msgid "Exits inputting search query" msgstr "検索クエリã®å…¥åŠ›ã‚’çµ‚äº†" #: src/view/com/modals/Waitlist.tsx:138 -msgid "Exits signing up for waitlist with {email}" -msgstr "{email}ã§Waitlistã¸ã®ç™»éŒ²ã‚’終了" +#~ msgid "Exits signing up for waitlist with {email}" +#~ msgstr "{email}ã§Waitlistã¸ã®ç™»éŒ²ã‚’終了" #: src/view/com/lightbox/Lightbox.web.tsx:163 msgid "Expand alt text" @@ -1499,7 +1504,7 @@ msgstr "外部メディア" msgid "External media may allow websites to collect information about you and your device. No information is sent or requested until you press the \"play\" button." msgstr "外部メディアを有効ã«ã™ã‚‹ã¨ã€ãれらã®ãƒ¡ãƒ‡ã‚£ã‚¢ã®ã‚¦ã‚§ãƒ–サイトãŒã‚ãªãŸã‚„ãŠä½¿ã„ã®ãƒ‡ãƒã‚¤ã‚¹ã«é–¢ã™ã‚‹æƒ…å ±ã‚’åŽé›†ã™ã‚‹å ´åˆãŒã‚りã¾ã™ã€‚ãã®å ´åˆã§ã‚‚ã€ã‚ãªãŸãŒã€Œå†ç”Ÿã€ãƒœã‚¿ãƒ³ã‚’押ã™ã¾ã§æƒ…å ±ã¯é€ä¿¡ã•れãšã€è¦æ±‚ã‚‚ã•れã¾ã›ã‚“。" -#: src/Navigation.tsx:261 +#: src/Navigation.tsx:263 #: src/view/screens/PreferencesExternalEmbeds.tsx:52 #: src/view/screens/Settings/index.tsx:657 msgid "External Media Preferences" @@ -1518,7 +1523,7 @@ msgstr "アプリパスワードã®ä½œæˆã«å¤±æ•—ã—ã¾ã—ãŸã€‚" msgid "Failed to create the list. Check your internet connection and try again." msgstr "リストã®ä½œæˆã«å¤±æ•—ã—ã¾ã—ãŸã€‚インターãƒãƒƒãƒˆã¸ã®æŽ¥ç¶šã‚’確èªã®ä¸Šã€ã‚‚ã†ä¸€åº¦ãŠè©¦ã—ãã ã•ã„。" -#: src/view/com/util/forms/PostDropdownBtn.tsx:110 +#: src/view/com/util/forms/PostDropdownBtn.tsx:128 msgid "Failed to delete post, please try again" msgstr "投稿ã®å‰Šé™¤ã«å¤±æ•—ã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ãŠè©¦ã—ãã ã•ã„。" @@ -1527,7 +1532,7 @@ msgstr "投稿ã®å‰Šé™¤ã«å¤±æ•—ã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ãŠè©¦ã—ãã ã•ã„ msgid "Failed to load recommended feeds" msgstr "ãŠã™ã™ã‚ã®ãƒ•ィードã®ãƒãƒ¼ãƒ‰ã«å¤±æ•—ã—ã¾ã—ãŸ" -#: src/Navigation.tsx:192 +#: src/Navigation.tsx:194 msgid "Feed" msgstr "フィード" @@ -1548,7 +1553,7 @@ msgstr "フィードã¯ã‚ªãƒ•ラインã§ã™" msgid "Feedback" msgstr "フィードãƒãƒƒã‚¯" -#: src/Navigation.tsx:445 +#: src/Navigation.tsx:452 #: src/view/screens/Feeds.tsx:419 #: src/view/screens/Feeds.tsx:524 #: src/view/screens/Profile.tsx:184 @@ -1697,9 +1702,9 @@ msgstr "フォãƒãƒ¼ä¸" msgid "Following {0}" msgstr "{0}をフォãƒãƒ¼ã—ã¦ã„ã¾ã™" -#: src/Navigation.tsx:248 -#: src/view/com/home/HomeHeaderLayout.web.tsx:45 -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:83 +#: src/Navigation.tsx:250 +#: src/view/com/home/HomeHeaderLayout.web.tsx:50 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:84 #: src/view/screens/PreferencesFollowingFeed.tsx:104 #: src/view/screens/Settings/index.tsx:543 msgid "Following Feed Preferences" @@ -1738,6 +1743,11 @@ msgstr "パスワードを忘れãŸ" msgid "Forgot Password" msgstr "パスワードを忘れãŸ" +#: src/screens/Hashtag.tsx:108 +#: src/screens/Hashtag.tsx:148 +msgid "From @{sanitizedAuthor}" +msgstr "" + #: src/view/com/posts/FeedItem.tsx:189 msgctxt "from-feed" msgid "From <0/>" @@ -1761,8 +1771,8 @@ msgstr "戻る" #: src/view/screens/ProfileFeed.tsx:106 #: src/view/screens/ProfileFeed.tsx:111 -#: src/view/screens/ProfileList.tsx:897 #: src/view/screens/ProfileList.tsx:902 +#: src/view/screens/ProfileList.tsx:907 msgid "Go Back" msgstr "戻る" @@ -1788,8 +1798,16 @@ msgstr "次ã¸" msgid "Handle" msgstr "ãƒãƒ³ãƒ‰ãƒ«" +#: src/Navigation.tsx:270 +msgid "Hashtag" +msgstr "" + #: src/components/RichText.tsx:188 -msgid "Hashtag: {tag}" +#~ msgid "Hashtag: {tag}" +#~ msgstr "" + +#: src/components/RichText.tsx:190 +msgid "Hashtag: #{tag}" msgstr "" #: src/view/com/auth/create/CreateAccount.tsx:208 @@ -1829,12 +1847,13 @@ msgid "Hide" msgstr "éžè¡¨ç¤º" #: src/view/com/modals/ContentFilteringSettings.tsx:224 -#: src/view/com/notifications/FeedItem.tsx:325 +#: src/view/com/notifications/FeedItem.tsx:326 msgctxt "action" msgid "Hide" msgstr "éžè¡¨ç¤º" -#: src/view/com/util/forms/PostDropdownBtn.tsx:232 +#: src/view/com/util/forms/PostDropdownBtn.tsx:276 +#: src/view/com/util/forms/PostDropdownBtn.tsx:287 msgid "Hide post" msgstr "投稿をéžè¡¨ç¤º" @@ -1843,11 +1862,11 @@ msgstr "投稿をéžè¡¨ç¤º" msgid "Hide the content" msgstr "コンテンツをéžè¡¨ç¤º" -#: src/view/com/util/forms/PostDropdownBtn.tsx:236 +#: src/view/com/util/forms/PostDropdownBtn.tsx:280 msgid "Hide this post?" msgstr "ã“ã®æŠ•ç¨¿ã‚’éžè¡¨ç¤ºã«ã—ã¾ã™ã‹ï¼Ÿ" -#: src/view/com/notifications/FeedItem.tsx:315 +#: src/view/com/notifications/FeedItem.tsx:316 msgid "Hide user list" msgstr "ユーザーリストをéžè¡¨ç¤º" @@ -1875,7 +1894,7 @@ msgstr "フィードサーãƒãƒ¼ã®åå¿œãŒæ‚ªã„よã†ã§ã™ã€‚ã“ã®å•題を msgid "Hmm, we're having trouble finding this feed. It may have been deleted." msgstr "ã“ã®ãƒ•ィードãŒè¦‹ã¤ã‹ã‚‰ãªã„よã†ã§ã™ã€‚ã‚‚ã—ã‹ã—ãŸã‚‰å‰Šé™¤ã•れãŸã®ã‹ã‚‚ã—れã¾ã›ã‚“。" -#: src/Navigation.tsx:435 +#: src/Navigation.tsx:442 #: src/view/shell/bottom-bar/BottomBar.tsx:137 #: src/view/shell/desktop/LeftNav.tsx:306 #: src/view/shell/Drawer.tsx:398 @@ -1890,7 +1909,7 @@ msgstr "ホーム" #~ msgid "Home Feed Preferences" #~ msgstr "ホームフィードã®è¨å®š" -#: src/view/com/auth/create/Step1.tsx:82 +#: src/view/com/auth/create/Step1.tsx:75 #: src/view/com/auth/login/ForgotPasswordForm.tsx:120 msgid "Hosting provider" msgstr "ホスティングプãƒãƒã‚¤ãƒ€ãƒ¼" @@ -1949,7 +1968,7 @@ msgstr "パスワードをリセットã™ã‚‹ãŸã‚ã«ã‚ãªãŸã®ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ msgid "Input confirmation code for account deletion" msgstr "アカウント削除ã®ãŸã‚ã«ç¢ºèªã‚³ãƒ¼ãƒ‰ã‚’入力" -#: src/view/com/auth/create/Step1.tsx:200 +#: src/view/com/auth/create/Step1.tsx:177 msgid "Input email for Bluesky account" msgstr "Blueskyアカウント用ã®ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’入力ã—ã¦ãã ã•ã„" @@ -1961,7 +1980,7 @@ msgstr "Blueskyアカウント用ã®ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’入力ã—ã¦ãã ã #~ msgid "Input hosting provider address" #~ msgstr "ホスティングプãƒãƒã‚¤ãƒ€ãƒ¼ã®ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’入力" -#: src/view/com/auth/create/Step1.tsx:158 +#: src/view/com/auth/create/Step1.tsx:151 msgid "Input invite code to proceed" msgstr "招待コードを入力ã—ã¦æ¬¡ã«é€²ã‚€" @@ -1994,8 +2013,8 @@ msgstr "サインアップ時ã«ä½¿ç”¨ã—ãŸãƒ¦ãƒ¼ã‚¶ãƒ¼åã¾ãŸã¯ãƒ¡ãƒ¼ãƒ«ã‚¢ #~ msgstr "テã‚ストメッセージã§é€ã‚‰ã‚Œã¦ããŸèªè¨¼ã‚³ãƒ¼ãƒ‰ã‚’入力ã—ã¦ãã ã•ã„" #: src/view/com/modals/Waitlist.tsx:90 -msgid "Input your email to get on the Bluesky waitlist" -msgstr "Blueskyã®Waitlistã«ç™»éŒ²ã™ã‚‹ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’入力" +#~ msgid "Input your email to get on the Bluesky waitlist" +#~ msgstr "Blueskyã®Waitlistã«ç™»éŒ²ã™ã‚‹ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’入力" #: src/view/com/auth/login/LoginForm.tsx:229 msgid "Input your password" @@ -2021,8 +2040,8 @@ msgstr "無効ãªãƒ¦ãƒ¼ã‚¶ãƒ¼åã¾ãŸã¯ãƒ‘スワード" msgid "Invite a Friend" msgstr "å‹é”を招待" -#: src/view/com/auth/create/Step1.tsx:148 -#: src/view/com/auth/create/Step1.tsx:157 +#: src/view/com/auth/create/Step1.tsx:141 +#: src/view/com/auth/create/Step1.tsx:150 msgid "Invite code" msgstr "招待コード" @@ -2052,17 +2071,17 @@ msgid "Jobs" msgstr "仕事" #: src/view/com/modals/Waitlist.tsx:67 -msgid "Join the waitlist" -msgstr "Waitlistã«å‚åŠ " +#~ msgid "Join the waitlist" +#~ msgstr "Waitlistã«å‚åŠ " #: src/view/com/auth/create/Step1.tsx:174 #: src/view/com/auth/create/Step1.tsx:178 -msgid "Join the waitlist." -msgstr "Waitlistã«å‚åŠ ã—ã¾ã™ã€‚" +#~ msgid "Join the waitlist." +#~ msgstr "Waitlistã«å‚åŠ ã—ã¾ã™ã€‚" #: src/view/com/modals/Waitlist.tsx:128 -msgid "Join Waitlist" -msgstr "Waitlistã«å‚åŠ " +#~ msgid "Join Waitlist" +#~ msgstr "Waitlistã«å‚åŠ " #: src/screens/Onboarding/index.tsx:24 msgid "Journalism" @@ -2076,7 +2095,7 @@ msgstr "言語ã®é¸æŠž" msgid "Language settings" msgstr "言語ã®è¨å®š" -#: src/Navigation.tsx:140 +#: src/Navigation.tsx:142 #: src/view/screens/LanguageSettings.tsx:89 msgid "Language Settings" msgstr "言語ã®è¨å®š" @@ -2146,7 +2165,6 @@ msgid "Light" msgstr "ライト" #: src/view/com/util/post-ctrls/PostCtrls.tsx:182 -#: src/view/com/util/post-ctrls/PostCtrls.tsx:216 msgid "Like" msgstr "ã„ã„ã" @@ -2154,7 +2172,7 @@ msgstr "ã„ã„ã" msgid "Like this feed" msgstr "ã“ã®ãƒ•ィードをã„ã„ã" -#: src/Navigation.tsx:197 +#: src/Navigation.tsx:199 msgid "Liked by" msgstr "ã„ã„ãã—ãŸãƒ¦ãƒ¼ã‚¶ãƒ¼" @@ -2199,7 +2217,7 @@ msgstr "ã“ã®æŠ•ç¨¿ã‚’ã„ã„ãã™ã‚‹" #~ msgid "Limit the visibility of my account to logged-out users" #~ msgstr "ãƒã‚°ã‚¢ã‚¦ãƒˆã—ãŸãƒ¦ãƒ¼ã‚¶ãƒ¼ã«å¯¾ã—ã¦ç§ã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã®é–²è¦§ã‚’制é™" -#: src/Navigation.tsx:166 +#: src/Navigation.tsx:168 msgid "List" msgstr "リスト" @@ -2235,7 +2253,7 @@ msgstr "リストã®ãƒ–ãƒãƒƒã‚¯ã‚’解除ã—ã¾ã—ãŸ" msgid "List unmuted" msgstr "リストã®ãƒŸãƒ¥ãƒ¼ãƒˆã‚’解除ã—ã¾ã—ãŸ" -#: src/Navigation.tsx:110 +#: src/Navigation.tsx:112 #: src/view/screens/Profile.tsx:185 #: src/view/shell/desktop/LeftNav.tsx:379 #: src/view/shell/Drawer.tsx:492 @@ -2267,7 +2285,7 @@ msgstr "ãƒãƒ¼ãƒ‰ä¸..." #~ msgid "Local dev server" #~ msgstr "ãƒãƒ¼ã‚«ãƒ«é–‹ç™ºè€…サーãƒãƒ¼" -#: src/Navigation.tsx:207 +#: src/Navigation.tsx:209 msgid "Log" msgstr "ãƒã‚°" @@ -2298,7 +2316,7 @@ msgstr "リストã«ãªã„アカウントã«ãƒã‚°ã‚¤ãƒ³" msgid "Make sure this is where you intend to go!" msgstr "æ„図ã—ãŸå ´æ‰€ã§ã‚ã‚‹ã“ã¨ã‚’確èªã—ã¦ãã ã•ã„ï¼" -#: src/components/dialogs/MutedWords.tsx:71 +#: src/components/dialogs/MutedWords.tsx:83 msgid "Manage your muted words and tags" msgstr "" @@ -2322,7 +2340,7 @@ msgstr "メンションã•れãŸãƒ¦ãƒ¼ã‚¶ãƒ¼" msgid "Mentioned users" msgstr "メンションã•れãŸãƒ¦ãƒ¼ã‚¶ãƒ¼" -#: src/view/com/util/ViewHeader.tsx:81 +#: src/view/com/util/ViewHeader.tsx:87 #: src/view/screens/Search/Search.tsx:646 msgid "Menu" msgstr "メニュー" @@ -2335,7 +2353,7 @@ msgstr "メニュー" msgid "Message from server: {0}" msgstr "サーãƒãƒ¼ã‹ã‚‰ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ï¼š{0}" -#: src/Navigation.tsx:115 +#: src/Navigation.tsx:117 #: src/view/screens/Moderation.tsx:66 #: src/view/screens/Settings/index.tsx:625 #: src/view/shell/desktop/LeftNav.tsx:397 @@ -2349,13 +2367,13 @@ msgstr "モデレーション" msgid "Moderation list by {0}" msgstr "{0}ã®ä½œæˆã—ãŸãƒ¢ãƒ‡ãƒ¬ãƒ¼ã‚·ãƒ§ãƒ³ãƒªã‚¹ãƒˆ" -#: src/view/screens/ProfileList.tsx:774 +#: src/view/screens/ProfileList.tsx:775 msgid "Moderation list by <0/>" msgstr "<0/>ã®ä½œæˆã—ãŸãƒ¢ãƒ‡ãƒ¬ãƒ¼ã‚·ãƒ§ãƒ³ãƒªã‚¹ãƒˆ" #: src/view/com/lists/ListCard.tsx:91 #: src/view/com/modals/UserAddRemoveLists.tsx:204 -#: src/view/screens/ProfileList.tsx:772 +#: src/view/screens/ProfileList.tsx:773 msgid "Moderation list by you" msgstr "ã‚ãªãŸã®ä½œæˆã—ãŸãƒ¢ãƒ‡ãƒ¬ãƒ¼ã‚·ãƒ§ãƒ³ãƒªã‚¹ãƒˆ" @@ -2371,7 +2389,7 @@ msgstr "モデレーションリストを更新ã—ã¾ã—ãŸ" msgid "Moderation lists" msgstr "モデレーションリスト" -#: src/Navigation.tsx:120 +#: src/Navigation.tsx:122 #: src/view/screens/ModerationModlists.tsx:58 msgid "Moderation Lists" msgstr "モデレーションリスト" @@ -2384,7 +2402,7 @@ msgstr "モデレーションã®è¨å®š" msgid "Moderator has chosen to set a general warning on the content." msgstr "モデレーターã«ã‚ˆã‚Šã‚³ãƒ³ãƒ†ãƒ³ãƒ„ã«ä¸€èˆ¬çš„ãªè¦å‘ŠãŒè¨å®šã•れã¾ã—ãŸã€‚" -#: src/view/shell/desktop/Feeds.tsx:63 +#: src/view/shell/desktop/Feeds.tsx:65 msgid "More feeds" msgstr "ãã®ä»–ã®ãƒ•ィード" @@ -2395,8 +2413,8 @@ msgid "More options" msgstr "ãã®ä»–ã®ã‚ªãƒ—ション" #: src/view/com/util/forms/PostDropdownBtn.tsx:315 -msgid "More post options" -msgstr "ãã®ã»ã‹ã®æŠ•稿ã®ã‚ªãƒ—ション" +#~ msgid "More post options" +#~ msgstr "ãã®ã»ã‹ã®æŠ•稿ã®ã‚ªãƒ—ション" #: src/view/screens/PreferencesThreads.tsx:82 msgid "Most-liked replies first" @@ -2406,11 +2424,11 @@ msgstr "ã„ã„ãã®æ•°ãŒå¤šã„é †ã«è¿”信を表示" msgid "Must be at least 3 characters" msgstr "" -#: src/components/TagMenu/index.tsx:253 +#: src/components/TagMenu/index.tsx:249 msgid "Mute" msgstr "" -#: src/components/TagMenu/index.web.tsx:91 +#: src/components/TagMenu/index.web.tsx:105 msgid "Mute {truncatedTag}" msgstr "" @@ -2422,15 +2440,19 @@ msgstr "アカウントをミュート" msgid "Mute accounts" msgstr "アカウントをミュート" -#: src/components/TagMenu/index.tsx:211 -msgid "Mute all {tag} posts" +#: src/components/TagMenu/index.tsx:209 +msgid "Mute all {displayTag} posts" msgstr "" -#: src/components/dialogs/MutedWords.tsx:131 +#: src/components/TagMenu/index.tsx:211 +#~ msgid "Mute all {tag} posts" +#~ msgstr "" + +#: src/components/dialogs/MutedWords.tsx:149 msgid "Mute in tags only" msgstr "" -#: src/components/dialogs/MutedWords.tsx:116 +#: src/components/dialogs/MutedWords.tsx:134 msgid "Mute in text & tags" msgstr "" @@ -2446,19 +2468,21 @@ msgstr "ã“れらã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã‚’ミュートã—ã¾ã™ã‹ï¼Ÿ" msgid "Mute this List" msgstr "ã“ã®ãƒªã‚¹ãƒˆã‚’ミュート" -#: src/components/dialogs/MutedWords.tsx:109 +#: src/components/dialogs/MutedWords.tsx:127 msgid "Mute this word in post text and tags" msgstr "" -#: src/components/dialogs/MutedWords.tsx:124 +#: src/components/dialogs/MutedWords.tsx:142 msgid "Mute this word in tags only" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:202 +#: src/view/com/util/forms/PostDropdownBtn.tsx:251 +#: src/view/com/util/forms/PostDropdownBtn.tsx:257 msgid "Mute thread" msgstr "スレッドをミュート" -#: src/view/com/util/forms/PostDropdownBtn.tsx:216 +#: src/view/com/util/forms/PostDropdownBtn.tsx:267 +#: src/view/com/util/forms/PostDropdownBtn.tsx:269 msgid "Mute words & tags" msgstr "" @@ -2470,7 +2494,7 @@ msgstr "ミュートã•れã¦ã„ã¾ã™" msgid "Muted accounts" msgstr "ミュートä¸ã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆ" -#: src/Navigation.tsx:125 +#: src/Navigation.tsx:127 #: src/view/screens/ModerationMutedAccounts.tsx:107 msgid "Muted Accounts" msgstr "ミュートä¸ã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆ" @@ -2546,7 +2570,7 @@ msgstr "フォãƒãƒ¯ãƒ¼ã‚„データã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’失ã†ã“ã¨ã¯ã‚り㾠msgid "Never lose access to your followers or data." msgstr "フォãƒãƒ¯ãƒ¼ã‚„データã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’失ã†ã“ã¨ã¯ã‚りã¾ã›ã‚“。" -#: src/components/dialogs/MutedWords.tsx:244 +#: src/components/dialogs/MutedWords.tsx:293 msgid "Nevermind" msgstr "" @@ -2638,7 +2662,7 @@ msgid "No" msgstr "ã„ã„ãˆ" #: src/view/screens/ProfileFeed.tsx:584 -#: src/view/screens/ProfileList.tsx:754 +#: src/view/screens/ProfileList.tsx:755 msgid "No description" msgstr "説明ã¯ã‚りã¾ã›ã‚“" @@ -2655,6 +2679,10 @@ msgstr "ãŠçŸ¥ã‚‰ã›ã¯ã‚りã¾ã›ã‚“ï¼" msgid "No result" msgstr "çµæžœã¯ã‚りã¾ã›ã‚“" +#: src/components/Lists.tsx:192 +msgid "No results found" +msgstr "" + #: src/view/screens/Feeds.tsx:495 msgid "No results found for \"{query}\"" msgstr "「{query}ã€ã®æ¤œç´¢çµæžœã¯ã‚りã¾ã›ã‚“" @@ -2677,7 +2705,7 @@ msgstr "返信ä¸å¯" msgid "Not Applicable." msgstr "該当ãªã—。" -#: src/Navigation.tsx:105 +#: src/Navigation.tsx:107 #: src/view/screens/Profile.tsx:106 msgid "Not Found" msgstr "見ã¤ã‹ã‚Šã¾ã›ã‚“" @@ -2695,7 +2723,7 @@ msgstr "今ã¯ã—ãªã„" msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites." msgstr "注記:Blueskyã¯ã‚ªãƒ¼ãƒ—ンã§ãƒ‘ブリックãªãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã§ã™ã€‚ã“ã®è¨å®šã¯Blueskyã®ã‚¢ãƒ—リãŠã‚ˆã³ã‚¦ã‚§ãƒ–サイト上ã®ã¿ã§ã®ã‚ãªãŸã®ã‚³ãƒ³ãƒ†ãƒ³ãƒ„ã®å¯è¦–性を制é™ã™ã‚‹ã‚‚ã®ã§ã‚りã€ä»–ã®ã‚¢ãƒ—リã§ã¯ã“ã®è¨å®šã‚’å°Šé‡ã—ãªã„å ´åˆãŒã‚りã¾ã™ã€‚ä»–ã®ã‚¢ãƒ—リやウェブサイトã§ã¯ã€ãƒã‚°ã‚¢ã‚¦ãƒˆã—ãŸãƒ¦ãƒ¼ã‚¶ãƒ¼ã«ã‚ãªãŸã®ã‚³ãƒ³ãƒ†ãƒ³ãƒ„ãŒè¡¨ç¤ºã•ã‚Œã‚‹å ´åˆãŒã‚りã¾ã™ã€‚" -#: src/Navigation.tsx:450 +#: src/Navigation.tsx:457 #: src/view/screens/Notifications.tsx:124 #: src/view/screens/Notifications.tsx:148 #: src/view/shell/bottom-bar/BottomBar.tsx:205 @@ -2737,6 +2765,11 @@ msgstr "1ã¤ã‚‚ã—ãã¯è¤‡æ•°ã®ç”»åƒã«ALTテã‚ストãŒã‚りã¾ã›ã‚“。" msgid "Only {0} can reply." msgstr "{0}ã®ã¿è¿”ä¿¡å¯èƒ½" +#: src/components/Lists.tsx:82 +msgid "Oops, something went wrong!" +msgstr "" + +#: src/components/Lists.tsx:188 #: src/view/screens/AppPasswords.tsx:65 #: src/view/screens/Profile.tsx:106 msgid "Oops!" @@ -2763,10 +2796,14 @@ msgstr "アプリ内ブラウザーã§ãƒªãƒ³ã‚¯ã‚’é–‹ã" msgid "Open muted words settings" msgstr "" -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:49 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:50 msgid "Open navigation" msgstr "ナビゲーションを開ã" +#: src/view/com/util/forms/PostDropdownBtn.tsx:175 +msgid "Open post options menu" +msgstr "" + #: src/view/screens/Settings/index.tsx:804 msgid "Open storybook page" msgstr "絵本ã®ãƒšãƒ¼ã‚¸ã‚’é–‹ã" @@ -2779,7 +2816,7 @@ msgstr "{numItems}個ã®ã‚ªãƒ—ションを開ã" msgid "Opens additional details for a debug entry" msgstr "デãƒãƒƒã‚°ã‚¨ãƒ³ãƒˆãƒªãƒ¼ã®è¿½åŠ è©³ç´°ã‚’é–‹ã" -#: src/view/com/notifications/FeedItem.tsx:348 +#: src/view/com/notifications/FeedItem.tsx:349 msgid "Opens an expanded list of users in this notification" msgstr "ã“ã®é€šçŸ¥å†…ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®æ‹¡å¼µãƒªã‚¹ãƒˆã‚’é–‹ã" @@ -2839,7 +2876,7 @@ msgstr "モデレーションã®è¨å®šã‚’é–‹ã" msgid "Opens password reset form" msgstr "パスワードリセットã®ãƒ•ォームを開ã" -#: src/view/com/home/HomeHeaderLayout.web.tsx:60 +#: src/view/com/home/HomeHeaderLayout.web.tsx:63 #: src/view/screens/Feeds.tsx:356 msgid "Opens screen to edit Saved Feeds" msgstr "ä¿å˜ã•れãŸãƒ•ィードã®ç·¨é›†ç”»é¢ã‚’é–‹ã" @@ -2892,6 +2929,7 @@ msgstr "ãã®ä»–ã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆ" msgid "Other..." msgstr "ãã®ä»–..." +#: src/components/Lists.tsx:194 #: src/view/screens/NotFound.tsx:45 msgid "Page not found" msgstr "ページãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“" @@ -2900,8 +2938,8 @@ msgstr "ページãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“" msgid "Page Not Found" msgstr "ページãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“" -#: src/view/com/auth/create/Step1.tsx:214 -#: src/view/com/auth/create/Step1.tsx:224 +#: src/view/com/auth/create/Step1.tsx:191 +#: src/view/com/auth/create/Step1.tsx:201 #: src/view/com/auth/login/LoginForm.tsx:226 #: src/view/com/auth/login/SetNewPasswordForm.tsx:161 #: src/view/com/modals/DeleteAccount.tsx:202 @@ -2916,11 +2954,11 @@ msgstr "ãƒ‘ã‚¹ãƒ¯ãƒ¼ãƒ‰ãŒæ›´æ–°ã•れã¾ã—ãŸ" msgid "Password updated!" msgstr "ãƒ‘ã‚¹ãƒ¯ãƒ¼ãƒ‰ãŒæ›´æ–°ã•れã¾ã—ãŸï¼" -#: src/Navigation.tsx:160 +#: src/Navigation.tsx:162 msgid "People followed by @{0}" msgstr "@{0}ãŒãƒ•ã‚©ãƒãƒ¼ä¸ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼" -#: src/Navigation.tsx:153 +#: src/Navigation.tsx:155 msgid "People following @{0}" msgstr "@{0}をフォãƒãƒ¼ä¸ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼" @@ -2994,6 +3032,10 @@ msgstr "アプリパスワードã«ã¤ã‘ã‚‹åå‰ã‚’入力ã—ã¦ãã ã•ã„。 msgid "Please enter a unique name for this App Password or use our randomly generated one." msgstr "ã“ã®ã‚¢ãƒ—リパスワードã«å›ºæœ‰ã®åå‰ã‚’入力ã™ã‚‹ã‹ã€ãƒ©ãƒ³ãƒ€ãƒ ã«ç”Ÿæˆã•れãŸåå‰ã‚’使用ã—ã¦ãã ã•ã„。" +#: src/components/dialogs/MutedWords.tsx:68 +msgid "Please enter a valid word, tag, or phrase to mute" +msgstr "" + #: src/view/com/auth/create/state.ts:170 #~ msgid "Please enter the code you received by SMS." #~ msgstr "SMSã§å—ã‘å–ã£ãŸã‚³ãƒ¼ãƒ‰ã‚’入力ã—ã¦ãã ã•ã„。" @@ -3057,13 +3099,13 @@ msgstr "投稿" msgid "Post by {0}" msgstr "{0}ã«ã‚ˆã‚‹æŠ•稿" -#: src/Navigation.tsx:172 -#: src/Navigation.tsx:179 -#: src/Navigation.tsx:186 +#: src/Navigation.tsx:174 +#: src/Navigation.tsx:181 +#: src/Navigation.tsx:188 msgid "Post by @{0}" msgstr "@{0}ã«ã‚ˆã‚‹æŠ•稿" -#: src/view/com/util/forms/PostDropdownBtn.tsx:90 +#: src/view/com/util/forms/PostDropdownBtn.tsx:108 msgid "Post deleted" msgstr "投稿を削除" @@ -3083,7 +3125,7 @@ msgstr "投稿ã®è¨€èªž" msgid "Post not found" msgstr "投稿ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“" -#: src/components/TagMenu/index.tsx:257 +#: src/components/TagMenu/index.tsx:253 msgid "posts" msgstr "" @@ -3091,7 +3133,7 @@ msgstr "" msgid "Posts" msgstr "投稿" -#: src/components/dialogs/MutedWords.tsx:77 +#: src/components/dialogs/MutedWords.tsx:90 msgid "Posts can be muted based on their text, their tags, or both." msgstr "" @@ -3120,7 +3162,7 @@ msgstr "ã‚ãªãŸã®ãƒ•ã‚©ãƒãƒ¼ã‚’優先" msgid "Privacy" msgstr "プライãƒã‚·ãƒ¼" -#: src/Navigation.tsx:217 +#: src/Navigation.tsx:219 #: src/view/screens/PrivacyPolicy.tsx:29 #: src/view/screens/Settings/index.tsx:891 #: src/view/shell/Drawer.tsx:262 @@ -3201,7 +3243,7 @@ msgstr "ãŠã™ã™ã‚ã®ãƒ•ィード" msgid "Recommended Users" msgstr "ãŠã™ã™ã‚ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼" -#: src/components/dialogs/MutedWords.tsx:249 +#: src/components/dialogs/MutedWords.tsx:298 #: src/view/com/modals/ListAddRemoveUsers.tsx:264 #: src/view/com/modals/SelfLabel.tsx:83 #: src/view/com/modals/UserAddRemoveLists.tsx:219 @@ -3239,7 +3281,7 @@ msgstr "イメージを削除" msgid "Remove image preview" msgstr "イメージプレビューを削除" -#: src/components/dialogs/MutedWords.tsx:294 +#: src/components/dialogs/MutedWords.tsx:343 msgid "Remove mute word from your list" msgstr "" @@ -3309,7 +3351,8 @@ msgid "Report List" msgstr "ãƒªã‚¹ãƒˆã‚’å ±å‘Š" #: src/view/com/modals/report/SendReportButton.tsx:37 -#: src/view/com/util/forms/PostDropdownBtn.tsx:255 +#: src/view/com/util/forms/PostDropdownBtn.tsx:301 +#: src/view/com/util/forms/PostDropdownBtn.tsx:309 msgid "Report post" msgstr "æŠ•ç¨¿ã‚’å ±å‘Š" @@ -3376,7 +3419,7 @@ msgstr "コードをリクエスト" msgid "Require alt text before posting" msgstr "ç”»åƒæŠ•ç¨¿æ™‚ã«ALTテã‚ã‚¹ãƒˆã‚’å¿…é ˆã¨ã™ã‚‹" -#: src/view/com/auth/create/Step1.tsx:153 +#: src/view/com/auth/create/Step1.tsx:146 msgid "Required for this provider" msgstr "ã“ã®ãƒ—ãƒãƒã‚¤ãƒ€ãƒ¼ã«å¿…è¦" @@ -3441,7 +3484,7 @@ msgstr "å†è©¦è¡Œ" #~ msgid "Retry." #~ msgstr "å†è©¦è¡Œ" -#: src/view/screens/ProfileList.tsx:898 +#: src/view/screens/ProfileList.tsx:903 msgid "Return to previous page" msgstr "å‰ã®ãƒšãƒ¼ã‚¸ã«æˆ»ã‚‹" @@ -3496,11 +3539,11 @@ msgstr "{handle}ã¸ã®ãƒãƒ³ãƒ‰ãƒ«ã®å¤‰æ›´ã‚’ä¿å˜" msgid "Science" msgstr "ç§‘å¦" -#: src/view/screens/ProfileList.tsx:854 +#: src/view/screens/ProfileList.tsx:859 msgid "Scroll to top" msgstr "一番上ã¾ã§ã‚¹ã‚¯ãƒãƒ¼ãƒ«" -#: src/Navigation.tsx:440 +#: src/Navigation.tsx:447 #: src/view/com/auth/LoggedOut.tsx:122 #: src/view/com/modals/ListAddRemoveUsers.tsx:75 #: src/view/com/util/forms/SearchInput.tsx:67 @@ -3523,13 +3566,21 @@ msgid "Search for \"{query}\"" msgstr "「{query}ã€ã‚’検索" #: src/components/TagMenu/index.tsx:145 -msgid "Search for all posts by @{authorHandle} with tag {tag}" +msgid "Search for all posts by @{authorHandle} with tag {displayTag}" msgstr "" -#: src/components/TagMenu/index.tsx:90 -msgid "Search for all posts with tag {tag}" +#: src/components/TagMenu/index.tsx:145 +#~ msgid "Search for all posts by @{authorHandle} with tag {tag}" +#~ msgstr "" + +#: src/components/TagMenu/index.tsx:94 +msgid "Search for all posts with tag {displayTag}" msgstr "" +#: src/components/TagMenu/index.tsx:90 +#~ msgid "Search for all posts with tag {tag}" +#~ msgstr "" + #: src/view/screens/Search/Search.tsx:390 #~ msgid "Search for posts and users." #~ msgstr "投稿ã¨ãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚’検索ã—ã¾ã™ã€‚" @@ -3544,22 +3595,30 @@ msgstr "ユーザーを検索" msgid "Security Step Required" msgstr "å¿…è¦ãªã‚»ã‚ãƒ¥ãƒªãƒ†ã‚£ã®æ‰‹é †" -#: src/components/TagMenu/index.web.tsx:50 +#: src/components/TagMenu/index.web.tsx:66 msgid "See {truncatedTag} posts" msgstr "" -#: src/components/TagMenu/index.web.tsx:67 +#: src/components/TagMenu/index.web.tsx:83 msgid "See {truncatedTag} posts by user" msgstr "" #: src/components/TagMenu/index.tsx:128 -msgid "See <0>{tag}</0> posts" +msgid "See <0>{displayTag}</0> posts" msgstr "" -#: src/components/TagMenu/index.tsx:189 -msgid "See <0>{tag}</0> posts by this user" +#: src/components/TagMenu/index.tsx:187 +msgid "See <0>{displayTag}</0> posts by this user" msgstr "" +#: src/components/TagMenu/index.tsx:128 +#~ msgid "See <0>{tag}</0> posts" +#~ msgstr "" + +#: src/components/TagMenu/index.tsx:189 +#~ msgid "See <0>{tag}</0> posts by this user" +#~ msgstr "" + #: src/view/screens/SavedFeeds.tsx:163 msgid "See this guide" msgstr "ガイドを見る" @@ -3584,7 +3643,7 @@ msgstr "æ—¢å˜ã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã‹ã‚‰é¸æŠž" msgid "Select option {i} of {numItems}" msgstr "{numItems}個ä¸{i}個目ã®ã‚ªãƒ—ã‚·ãƒ§ãƒ³ã‚’é¸æŠž" -#: src/view/com/auth/create/Step1.tsx:103 +#: src/view/com/auth/create/Step1.tsx:96 #: src/view/com/auth/login/LoginForm.tsx:150 msgid "Select service" msgstr "ã‚µãƒ¼ãƒ“ã‚¹ã‚’é¸æŠž" @@ -3706,7 +3765,7 @@ msgstr "ダークテーマを薄暗ã„ã‚‚ã®ã«è¨å®šã—ã¾ã™" msgid "Set new password" msgstr "æ–°ã—ã„パスワードをè¨å®š" -#: src/view/com/auth/create/Step1.tsx:225 +#: src/view/com/auth/create/Step1.tsx:202 msgid "Set password" msgstr "パスワードをè¨å®š" @@ -3754,12 +3813,12 @@ msgstr "パスワードをリセットã™ã‚‹ãŸã‚ã®ãƒ›ã‚¹ãƒ†ã‚£ãƒ³ã‚°ãƒ—ãƒãƒ #~ msgid "Sets hosting provider to {label}" #~ msgstr "ホスティングプãƒãƒã‚¤ãƒ€ãƒ¼ã‚’{label}ã«è¨å®š" -#: src/view/com/auth/create/Step1.tsx:104 +#: src/view/com/auth/create/Step1.tsx:97 #: src/view/com/auth/login/LoginForm.tsx:151 msgid "Sets server for the Bluesky client" msgstr "Blueskyã®ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆã®ã‚µãƒ¼ãƒãƒ¼ã‚’è¨å®š" -#: src/Navigation.tsx:135 +#: src/Navigation.tsx:137 #: src/view/screens/Settings/index.tsx:294 #: src/view/shell/desktop/LeftNav.tsx:433 #: src/view/shell/Drawer.tsx:567 @@ -3777,7 +3836,9 @@ msgid "Share" msgstr "共有" #: src/view/com/profile/ProfileHeader.tsx:295 -#: src/view/com/util/forms/PostDropdownBtn.tsx:184 +#: src/view/com/util/forms/PostDropdownBtn.tsx:231 +#: src/view/com/util/forms/PostDropdownBtn.tsx:237 +#: src/view/com/util/post-ctrls/PostCtrls.tsx:215 #: src/view/screens/ProfileList.tsx:418 msgid "Share" msgstr "共有" @@ -3869,7 +3930,7 @@ msgstr "Followingフィードã§ãƒªãƒã‚¹ãƒˆã‚’表示" msgid "Show the content" msgstr "コンテンツを表示" -#: src/view/com/notifications/FeedItem.tsx:346 +#: src/view/com/notifications/FeedItem.tsx:347 msgid "Show users" msgstr "ユーザーを表示" @@ -3976,11 +4037,15 @@ msgstr "ソフトウェア開発" #~ msgid "Something went wrong and we're not sure what." #~ msgstr "何ã‹ã®å•題ãŒèµ·ãã¾ã—ãŸãŒã€ãれãŒä½•ãªã®ã‹ã‚ã‹ã‚Šã¾ã›ã‚“。" +#: src/components/Lists.tsx:203 +msgid "Something went wrong!" +msgstr "" + #: src/view/com/modals/Waitlist.tsx:51 -msgid "Something went wrong. Check your email and try again." -msgstr "ãªã‚“らã‹ã®å•題ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚メールアドレスを確èªã—ã€ã‚‚ã†ä¸€åº¦ãŠè©¦ã—ãã ã•ã„。" +#~ msgid "Something went wrong. Check your email and try again." +#~ msgstr "ãªã‚“らã‹ã®å•題ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚メールアドレスを確èªã—ã€ã‚‚ã†ä¸€åº¦ãŠè©¦ã—ãã ã•ã„。" -#: src/App.native.tsx:63 +#: src/App.native.tsx:66 msgid "Sorry! Your session expired. Please log in again." msgstr "申ã—訳ã‚りã¾ã›ã‚“ï¼ã‚»ãƒƒã‚·ãƒ§ãƒ³ã®æœ‰åŠ¹æœŸé™ãŒåˆ‡ã‚Œã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦ãƒã‚°ã‚¤ãƒ³ã—ã¦ãã ã•ã„。" @@ -4020,7 +4085,7 @@ msgstr "{numSteps}個ä¸{0}個目ã®ã‚¹ãƒ†ãƒƒãƒ—" msgid "Storage cleared, you need to restart the app now." msgstr "ストレージãŒã‚¯ãƒªã‚¢ã•れãŸãŸã‚ã€ä»Šã™ãアプリをå†èµ·å‹•ã™ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚" -#: src/Navigation.tsx:202 +#: src/Navigation.tsx:204 #: src/view/screens/Settings/index.tsx:807 msgid "Storybook" msgstr "ストーリーブック" @@ -4034,7 +4099,7 @@ msgid "Subscribe" msgstr "登録" #: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:173 -#: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:307 +#: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:308 msgid "Subscribe to the {0} feed" msgstr "「{0}ã€ãƒ•ィードを登録" @@ -4058,7 +4123,7 @@ msgstr "ã‚ãªãŸã¸ã®ãŠã™ã™ã‚" msgid "Suggestive" msgstr "ãã‚ã©ã„" -#: src/Navigation.tsx:212 +#: src/Navigation.tsx:214 #: src/view/screens/Support.tsx:30 #: src/view/screens/Support.tsx:33 msgid "Support" @@ -4090,14 +4155,18 @@ msgstr "システム" msgid "System log" msgstr "システムãƒã‚°" -#: src/components/dialogs/MutedWords.tsx:288 +#: src/components/dialogs/MutedWords.tsx:337 msgid "tag" msgstr "" -#: src/components/TagMenu/index.tsx:74 -msgid "Tag menu: {tag}" +#: src/components/TagMenu/index.tsx:78 +msgid "Tag menu: {displayTag}" msgstr "" +#: src/components/TagMenu/index.tsx:74 +#~ msgid "Tag menu: {tag}" +#~ msgstr "" + #: src/view/com/modals/crop-image/CropImage.web.tsx:112 msgid "Tall" msgstr "トール" @@ -4114,14 +4183,14 @@ msgstr "テクノãƒã‚¸ãƒ¼" msgid "Terms" msgstr "æ¡ä»¶" -#: src/Navigation.tsx:222 +#: src/Navigation.tsx:224 #: src/view/screens/Settings/index.tsx:885 #: src/view/screens/TermsOfService.tsx:29 #: src/view/shell/Drawer.tsx:256 msgid "Terms of Service" msgstr "利用è¦ç´„" -#: src/components/dialogs/MutedWords.tsx:288 +#: src/components/dialogs/MutedWords.tsx:337 msgid "text" msgstr "" @@ -4206,7 +4275,7 @@ msgstr "サーãƒãƒ¼ã¸ã®å•ã„åˆã‚ã›ä¸ã«å•題ãŒç™ºç”Ÿã—ã¾ã—ãŸ" msgid "There was an issue fetching notifications. Tap here to try again." msgstr "通知ã®å–å¾—ä¸ã«å•題ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦è©¦ã™ã«ã¯ã“ã¡ã‚‰ã‚’タップã—ã¦ãã ã•ã„。" -#: src/view/com/posts/Feed.tsx:263 +#: src/view/com/posts/Feed.tsx:265 msgid "There was an issue fetching posts. Tap here to try again." msgstr "投稿ã®å–å¾—ä¸ã«å•題ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚ã‚‚ã†ä¸€åº¦è©¦ã™ã«ã¯ã“ã¡ã‚‰ã‚’タップã—ã¦ãã ã•ã„。" @@ -4324,7 +4393,7 @@ msgstr "ã“れã¯ã€ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã®å¤‰æ›´ã‚„パスワードã®ãƒªã‚»ãƒƒ msgid "This link is taking you to the following website:" msgstr "ã“ã®ãƒªãƒ³ã‚¯ã¯æ¬¡ã®ã‚¦ã‚§ãƒ–サイトã¸ãƒªãƒ³ã‚¯ã—ã¦ã„ã¾ã™ï¼š" -#: src/view/screens/ProfileList.tsx:834 +#: src/view/screens/ProfileList.tsx:839 msgid "This list is empty!" msgstr "ã“ã®ãƒªã‚¹ãƒˆã¯ç©ºã§ã™ï¼" @@ -4356,11 +4425,11 @@ msgstr "ã“ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã¯ã€ã‚ãªãŸãŒãƒŸãƒ¥ãƒ¼ãƒˆã—ãŸ<0/>リストã«å msgid "This warning is only available for posts with media attached." msgstr "ã“ã®è¦å‘Šã¯ã€ãƒ¡ãƒ‡ã‚£ã‚¢ãŒæ·»ä»˜ã•れã¦ã„る投稿ã«ã®ã¿ä½¿ç”¨ã§ãã¾ã™ã€‚" -#: src/components/dialogs/MutedWords.tsx:236 +#: src/components/dialogs/MutedWords.tsx:285 msgid "This will delete {0} from your muted words. You can always add it back later." msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:237 +#: src/view/com/util/forms/PostDropdownBtn.tsx:282 msgid "This will hide this post from your feeds." msgstr "ã“ã®æŠ•ç¨¿ã‚’ã‚ãªãŸã®ãƒ•ィードã«ãŠã„ã¦éžè¡¨ç¤ºã«ã—ã¾ã™ã€‚" @@ -4373,11 +4442,11 @@ msgstr "スレッドã®è¨å®š" msgid "Threaded Mode" msgstr "スレッドモード" -#: src/Navigation.tsx:255 +#: src/Navigation.tsx:257 msgid "Threads Preferences" msgstr "スレッドã®è¨å®š" -#: src/components/dialogs/MutedWords.tsx:95 +#: src/components/dialogs/MutedWords.tsx:113 msgid "Toggle between muted word options." msgstr "" @@ -4391,7 +4460,8 @@ msgstr "変æ›" #: src/view/com/post-thread/PostThreadItem.tsx:685 #: src/view/com/post-thread/PostThreadItem.tsx:687 -#: src/view/com/util/forms/PostDropdownBtn.tsx:156 +#: src/view/com/util/forms/PostDropdownBtn.tsx:215 +#: src/view/com/util/forms/PostDropdownBtn.tsx:217 msgid "Translate" msgstr "翻訳" @@ -4456,16 +4526,15 @@ msgid "Unfortunately, you do not meet the requirements to create an account." msgstr "残念ãªãŒã‚‰ã€ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã‚’作æˆã™ã‚‹ãŸã‚ã®è¦ä»¶ã‚’満ãŸã—ã¦ã„ã¾ã›ã‚“。" #: src/view/com/util/post-ctrls/PostCtrls.tsx:182 -#: src/view/com/util/post-ctrls/PostCtrls.tsx:216 msgid "Unlike" msgstr "ã„ã„ãを外ã™" -#: src/components/TagMenu/index.tsx:253 +#: src/components/TagMenu/index.tsx:249 #: src/view/screens/ProfileList.tsx:597 msgid "Unmute" msgstr "ミュートを解除" -#: src/components/TagMenu/index.web.tsx:90 +#: src/components/TagMenu/index.web.tsx:104 msgid "Unmute {truncatedTag}" msgstr "" @@ -4473,11 +4542,16 @@ msgstr "" msgid "Unmute Account" msgstr "アカウントã®ãƒŸãƒ¥ãƒ¼ãƒˆã‚’解除" -#: src/components/TagMenu/index.tsx:210 -msgid "Unmute all {tag} posts" +#: src/components/TagMenu/index.tsx:208 +msgid "Unmute all {displayTag} posts" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:202 +#: src/components/TagMenu/index.tsx:210 +#~ msgid "Unmute all {tag} posts" +#~ msgstr "" + +#: src/view/com/util/forms/PostDropdownBtn.tsx:251 +#: src/view/com/util/forms/PostDropdownBtn.tsx:256 msgid "Unmute thread" msgstr "スレッドã®ãƒŸãƒ¥ãƒ¼ãƒˆã‚’解除" @@ -4561,13 +4635,13 @@ msgstr "ユーザーãƒãƒ³ãƒ‰ãƒ«" msgid "User list by {0}" msgstr "<0/>ã®ä½œæˆã—ãŸãƒ¦ãƒ¼ã‚¶ãƒ¼ãƒªã‚¹ãƒˆ" -#: src/view/screens/ProfileList.tsx:762 +#: src/view/screens/ProfileList.tsx:763 msgid "User list by <0/>" msgstr "<0/>ã®ä½œæˆã—ãŸãƒ¦ãƒ¼ã‚¶ãƒ¼ãƒªã‚¹ãƒˆ" #: src/view/com/lists/ListCard.tsx:83 #: src/view/com/modals/UserAddRemoveLists.tsx:196 -#: src/view/screens/ProfileList.tsx:760 +#: src/view/screens/ProfileList.tsx:761 msgid "User list by you" msgstr "ã‚ãªãŸã®ä½œæˆã—ãŸãƒ¦ãƒ¼ã‚¶ãƒ¼ãƒªã‚¹ãƒˆ" @@ -4588,7 +4662,7 @@ msgstr "ユーザーリスト" msgid "Username or email address" msgstr "ユーザーåã¾ãŸã¯ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹" -#: src/view/screens/ProfileList.tsx:796 +#: src/view/screens/ProfileList.tsx:797 msgid "Users" msgstr "ユーザー" @@ -4662,6 +4736,10 @@ msgstr "è¦å‘Š" msgid "We also think you'll like \"For You\" by Skygaze:" msgstr "Skygazeã«ã‚ˆã‚‹ã€ŒFor Youã€ãƒ•ィードもãŠã™ã™ã‚:" +#: src/screens/Hashtag.tsx:132 +msgid "We couldn't find any results for that hashtag." +msgstr "" + #: src/screens/Deactivated.tsx:133 msgid "We estimate {estimatedTime} until your account is ready." msgstr "ã‚ãªãŸã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆãŒæº–å‚™ã§ãã‚‹ã¾ã§{estimatedTime}ã»ã©ã‹ã‹ã‚Šã¾ã™ã€‚" @@ -4682,7 +4760,7 @@ msgstr "ã‚ãªãŸã®ãƒ•ã‚©ãƒãƒ¼ä¸ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®æŠ•稿をèªã¿çµ‚ã‚り㾠#~ msgid "We recommend \"For You\" by Skygaze:" #~ msgstr "Skygazeã«ã‚ˆã‚‹ã€ŒFor Youã€ãƒ•ィードãŒãŠã™ã™ã‚:" -#: src/components/dialogs/MutedWords.tsx:161 +#: src/components/dialogs/MutedWords.tsx:204 msgid "We recommend avoiding common words that appear in many posts, since it can result in no posts being shown." msgstr "" @@ -4714,7 +4792,7 @@ msgstr "ç§ãŸã¡ã¯ã‚ãªãŸãŒå‚åŠ ã—ã¦ãれるã“ã¨ã‚’ã¨ã¦ã‚‚楽ã—ã¿ msgid "We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @{handleOrDid}." msgstr "大変申ã—訳ã‚りã¾ã›ã‚“ãŒã€ã“ã®ãƒªã‚¹ãƒˆã‚’解決ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚ãれã§ã‚‚ã“ã®å•題ãŒè§£æ±ºã—ãªã„å ´åˆã¯ã€ä½œæˆè€…ã®@{handleOrDid}ã¾ã§ãŠå•ã„åˆã‚ã›ãã ã•ã„。" -#: src/components/dialogs/MutedWords.tsx:182 +#: src/components/dialogs/MutedWords.tsx:230 msgid "We're sorry, but we weren't able to load your muted words at this time. Please try again." msgstr "" @@ -4722,6 +4800,7 @@ msgstr "" msgid "We're sorry, but your search could not be completed. Please try again in a few minutes." msgstr "大変申ã—訳ã‚りã¾ã›ã‚“ãŒã€æ¤œç´¢ã‚’完了ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚数分後ã«å†è©¦è¡Œã—ã¦ãã ã•ã„。" +#: src/components/Lists.tsx:211 #: src/view/screens/NotFound.tsx:48 msgid "We're sorry! We can't find the page you were looking for." msgstr "大変申ã—訳ã‚りã¾ã›ã‚“ï¼ãпޢã—ã®ãƒšãƒ¼ã‚¸ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。" @@ -4873,7 +4952,7 @@ msgstr "アプリパスワードã¯ã¾ã 作æˆã•れã¦ã„ã¾ã›ã‚“。下ã®ãƒœ msgid "You have not muted any accounts yet. To mute an account, go to their profile and selected \"Mute account\" from the menu on their account." msgstr "ミュートã—ã¦ã„るアカウントã¯ã¾ã ã‚りã¾ã›ã‚“。アカウントをミュートã™ã‚‹ã«ã¯ã€ãƒ—ãƒãƒ•ィールã«ç§»å‹•ã—ã€ã‚¢ã‚«ã‚¦ãƒ³ãƒˆãƒ¡ãƒ‹ãƒ¥ãƒ¼ã‹ã‚‰ã€Œã‚¢ã‚«ã‚¦ãƒ³ãƒˆã‚’ミュートã€ã‚’é¸æŠžã—ã¾ã™ã€‚" -#: src/components/dialogs/MutedWords.tsx:202 +#: src/components/dialogs/MutedWords.tsx:250 msgid "You haven't muted any words or tags yet" msgstr "" @@ -4885,11 +4964,11 @@ msgstr "æˆäººå‘ã‘コンテンツを有効ã«ã™ã‚‹ã«ã¯ã€18æ³ä»¥ä¸Šã§ã‚ã msgid "You must be 18 years or older to enable adult content" msgstr "æˆäººå‘ã‘コンテンツを有効ã«ã™ã‚‹ã«ã¯ã€18æ³ä»¥ä¸Šã§ã‚ã‚‹å¿…è¦ãŒã‚りã¾ã™ã€‚" -#: src/view/com/util/forms/PostDropdownBtn.tsx:129 +#: src/view/com/util/forms/PostDropdownBtn.tsx:147 msgid "You will no longer receive notifications for this thread" msgstr "ã“れ以é™ã€ã“ã®ã‚¹ãƒ¬ãƒƒãƒ‰ã«é–¢ã™ã‚‹é€šçŸ¥ã‚’å—ã‘å–ã‚‹ã“ã¨ã¯ã§ããªããªã‚Šã¾ã™" -#: src/view/com/util/forms/PostDropdownBtn.tsx:132 +#: src/view/com/util/forms/PostDropdownBtn.tsx:150 msgid "You will now receive notifications for this thread" msgstr "ã“れ以é™ã€ã“ã®ã‚¹ãƒ¬ãƒƒãƒ‰ã«é–¢ã™ã‚‹é€šçŸ¥ã‚’å—ã‘å–ã‚‹ã“ã¨ãŒã§ãã¾ã™" @@ -4915,7 +4994,7 @@ msgstr "準備ãŒã§ãã¾ã—ãŸï¼" msgid "You've reached the end of your feed! Find some more accounts to follow." msgstr "フィードã¯ã“ã“ã¾ã§ã§ã™ï¼ã‚‚ã£ã¨ãƒ•ã‚©ãƒãƒ¼ã™ã‚‹ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã‚’見ã¤ã‘ã¾ã—ょã†ã€‚" -#: src/view/com/auth/create/Step1.tsx:74 +#: src/view/com/auth/create/Step1.tsx:67 msgid "Your account" msgstr "ã‚ãªãŸã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆ" @@ -4927,7 +5006,7 @@ msgstr "ã‚ãªãŸã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã¯å‰Šé™¤ã•れã¾ã—ãŸ" msgid "Your account repository, containing all public data records, can be downloaded as a \"CAR\" file. This file does not include media embeds, such as images, or your private data, which must be fetched separately." msgstr "" -#: src/view/com/auth/create/Step1.tsx:238 +#: src/view/com/auth/create/Step1.tsx:215 msgid "Your birth date" msgstr "生年月日" @@ -4946,8 +5025,8 @@ msgid "Your email appears to be invalid." msgstr "メールアドレスãŒç„¡åйãªã‚ˆã†ã§ã™ã€‚" #: src/view/com/modals/Waitlist.tsx:109 -msgid "Your email has been saved! We'll be in touch soon." -msgstr "メールアドレスãŒä¿å˜ã•れã¾ã—ãŸï¼ã™ãã«ã”連絡ã„ãŸã—ã¾ã™ã€‚" +#~ msgid "Your email has been saved! We'll be in touch soon." +#~ msgstr "メールアドレスãŒä¿å˜ã•れã¾ã—ãŸï¼ã™ãã«ã”連絡ã„ãŸã—ã¾ã™ã€‚" #: src/view/com/modals/ChangeEmail.tsx:125 msgid "Your email has been updated but not verified. As a next step, please verify your new email." @@ -4979,7 +5058,7 @@ msgstr "フルãƒãƒ³ãƒ‰ãƒ«ã¯<0>@{0}</0>ã«ãªã‚Šã¾ã™" #~ msgid "Your invite codes are hidden when logged in using an App Password" #~ msgstr "アプリパスワードを使用ã—ã¦ãƒã‚°ã‚¤ãƒ³ã™ã‚‹ã¨ã€æ‹›å¾…コードã¯éžè¡¨ç¤ºã«ãªã‚Šã¾ã™ã€‚" -#: src/components/dialogs/MutedWords.tsx:173 +#: src/components/dialogs/MutedWords.tsx:221 msgid "Your muted words" msgstr "" diff --git a/src/locale/locales/ko/messages.po b/src/locale/locales/ko/messages.po index b70ba1694..28059c3ed 100644 --- a/src/locale/locales/ko/messages.po +++ b/src/locale/locales/ko/messages.po @@ -9,45 +9,27 @@ msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" "PO-Revision-Date: \n" -"Last-Translator: quiple\n" -"Language-Team: quiple, lens0021, HaruChanHeart, hazzzi\n" +"Last-Translator: heartade\n" +"Language-Team: quiple, lens0021, HaruChanHeart, hazzzi, heartade\n" "Plural-Forms: \n" #: src/view/com/modals/VerifyEmail.tsx:142 msgid "(no email)" msgstr "(ì´ë©”ì¼ ì—†ìŒ)" -#: src/view/shell/desktop/RightNav.tsx:168 -#~ msgid "{0, plural, one {# invite code available} other {# invite codes available}}" -#~ msgstr "{0, plural, one {초대 코드 #ê°œ 사용 가능} other {초대 코드 #ê°œ 사용 가능}}" - -#: src/view/com/profile/ProfileHeader.tsx:593 +#: src/screens/Profile/Header/Metrics.tsx:45 msgid "{following} following" msgstr "{following} 팔로우 중" -#: src/view/shell/desktop/RightNav.tsx:151 -#~ msgid "{invitesAvailable, plural, one {Invite codes: # available} other {Invite codes: # available}}" -#~ msgstr "{invitesAvailable, plural, one {초대 코드: #ê°œ 사용 가능} other {초대 코드: #ê°œ 사용 가능}}" - -#: src/view/screens/Settings.tsx:435 -#: src/view/shell/Drawer.tsx:664 -#~ msgid "{invitesAvailable} invite code available" -#~ msgstr "초대 코드 {invitesAvailable}ê°œ 사용 가능" - -#: src/view/screens/Settings.tsx:437 -#: src/view/shell/Drawer.tsx:666 -#~ msgid "{invitesAvailable} invite codes available" -#~ msgstr "초대 코드 {invitesAvailable}ê°œ 사용 가능" - #: src/view/shell/Drawer.tsx:440 msgid "{numUnreadNotifications} unread" msgstr "{numUnreadNotifications}ê°œ ì½ì§€ 않ìŒ" #: src/view/com/threadgate/WhoCanReply.tsx:158 msgid "<0/> members" -msgstr "<0/> 멤버" +msgstr "<0/>ì˜ ë©¤ë²„" -#: src/view/com/profile/ProfileHeader.tsx:595 +#: src/screens/Profile/Header/Metrics.tsx:46 msgid "<0>{following} </0><1>following</1>" msgstr "<0>{following} </0><1>팔로우 중</1>" @@ -63,51 +45,52 @@ msgstr "<1>추천 사용ìž</1><0>팔로우하기</0>" msgid "<0>Welcome to</0><1>Bluesky</1>" msgstr "<1>Bluesky</1><0>ì— ì˜¤ì‹ ê²ƒì„ í™˜ì˜í•©ë‹ˆë‹¤</0>" -#: src/view/com/profile/ProfileHeader.tsx:558 +#: src/screens/Profile/Header/Handle.tsx:42 msgid "âš Invalid Handle" msgstr "âš ìž˜ëª»ëœ í•¸ë“¤" -#: src/view/com/util/moderation/LabelInfo.tsx:45 -msgid "A content warning has been applied to this {0}." -msgstr "ì´ {0}ì— ì½˜í…ì¸ ê²½ê³ ê°€ ì ìš©ë˜ì—ˆìŠµë‹ˆë‹¤." - -#: src/lib/hooks/useOTAUpdate.ts:16 -msgid "A new version of the app is available. Please update to continue using the app." -msgstr "새 ë²„ì „ì˜ ì•±ì„ ì‚¬ìš©í• ìˆ˜ 있습니다. ì•±ì„ ê³„ì† ì‚¬ìš©í•˜ë ¤ë©´ ì—…ë°ì´íŠ¸í•˜ì„¸ìš”." - -#: src/view/com/util/ViewHeader.tsx:83 +#: src/view/com/util/ViewHeader.tsx:89 #: src/view/screens/Search/Search.tsx:647 msgid "Access navigation links and settings" msgstr "íƒìƒ‰ ë§í¬ ë° ì„¤ì •ìœ¼ë¡œ ì´ë™í•©ë‹ˆë‹¤" -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:51 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:52 msgid "Access profile and other navigation links" msgstr "프로필 ë° ê¸°íƒ€ íƒìƒ‰ ë§í¬ë¡œ ì´ë™í•©ë‹ˆë‹¤" #: src/view/com/modals/EditImage.tsx:299 -#: src/view/screens/Settings/index.tsx:451 +#: src/view/screens/Settings/index.tsx:469 msgid "Accessibility" msgstr "ì ‘ê·¼ì„±" +#: src/components/moderation/LabelsOnMe.tsx:42 +msgid "account" +msgstr "ê³„ì •" + #: src/view/com/auth/login/LoginForm.tsx:166 -#: src/view/screens/Settings/index.tsx:308 -#: src/view/screens/Settings/index.tsx:721 +#: src/view/screens/Settings/index.tsx:326 +#: src/view/screens/Settings/index.tsx:739 msgid "Account" msgstr "ê³„ì •" -#: src/view/com/profile/ProfileHeader.tsx:246 +#: src/view/com/profile/ProfileMenu.tsx:139 msgid "Account blocked" msgstr "ê³„ì • 차단ë¨" -#: src/view/com/profile/ProfileHeader.tsx:213 +#: src/view/com/profile/ProfileMenu.tsx:153 +msgid "Account followed" +msgstr "ê³„ì • 팔로우함" + +#: src/view/com/profile/ProfileMenu.tsx:113 msgid "Account muted" msgstr "ê³„ì • 뮤트ë¨" -#: src/view/com/modals/ModerationDetails.tsx:86 +#: src/components/moderation/ModerationDetailsDialog.tsx:94 +#: src/lib/moderation/useModerationCauseDescription.ts:91 msgid "Account Muted" msgstr "ê³„ì • 뮤트ë¨" -#: src/view/com/modals/ModerationDetails.tsx:72 +#: src/components/moderation/ModerationDetailsDialog.tsx:83 msgid "Account Muted by List" msgstr "리스트로 ê³„ì • 뮤트ë¨" @@ -119,19 +102,24 @@ msgstr "ê³„ì • 옵션" msgid "Account removed from quick access" msgstr "ë¹ ë¥¸ 액세스ì—서 ê³„ì • ì œê±°" -#: src/view/com/profile/ProfileHeader.tsx:268 +#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:130 +#: src/view/com/profile/ProfileMenu.tsx:128 msgid "Account unblocked" msgstr "ê³„ì • 차단 í•´ì œë¨" -#: src/view/com/profile/ProfileHeader.tsx:226 +#: src/view/com/profile/ProfileMenu.tsx:166 +msgid "Account unfollowed" +msgstr "ê³„ì • 언팔로우함" + +#: src/view/com/profile/ProfileMenu.tsx:102 msgid "Account unmuted" msgstr "ê³„ì • 언뮤트ë¨" -#: src/components/dialogs/MutedWords.tsx:147 +#: src/components/dialogs/MutedWords.tsx:165 #: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:150 #: src/view/com/modals/ListAddRemoveUsers.tsx:264 #: src/view/com/modals/UserAddRemoveLists.tsx:219 -#: src/view/screens/ProfileList.tsx:812 +#: src/view/screens/ProfileList.tsx:827 msgid "Add" msgstr "추가" @@ -139,12 +127,12 @@ msgstr "추가" msgid "Add a content warning" msgstr "콘í…ì¸ ê²½ê³ ì¶”ê°€" -#: src/view/screens/ProfileList.tsx:802 +#: src/view/screens/ProfileList.tsx:817 msgid "Add a user to this list" msgstr "ì´ ë¦¬ìŠ¤íŠ¸ì— ì‚¬ìš©ìž ì¶”ê°€" -#: src/view/screens/Settings/index.tsx:383 -#: src/view/screens/Settings/index.tsx:392 +#: src/view/screens/Settings/index.tsx:401 +#: src/view/screens/Settings/index.tsx:410 msgid "Add account" msgstr "ê³„ì • 추가" @@ -154,47 +142,38 @@ msgstr "ê³„ì • 추가" msgid "Add alt text" msgstr "대체 í…스트 추가하기" -#: src/view/screens/AppPasswords.tsx:102 -#: src/view/screens/AppPasswords.tsx:143 -#: src/view/screens/AppPasswords.tsx:156 +#: src/view/screens/AppPasswords.tsx:104 +#: src/view/screens/AppPasswords.tsx:145 +#: src/view/screens/AppPasswords.tsx:158 msgid "Add App Password" msgstr "앱 비밀번호 추가" -#: src/view/com/modals/report/InputIssueDetails.tsx:41 -#: src/view/com/modals/report/Modal.tsx:191 -msgid "Add details" -msgstr "세부 ì •ë³´ 추가" - -#: src/view/com/modals/report/Modal.tsx:194 -msgid "Add details to report" -msgstr "ì‹ ê³ ì„¸ë¶€ ì •ë³´ 추가" - -#: src/view/com/composer/Composer.tsx:453 +#: src/view/com/composer/Composer.tsx:462 msgid "Add link card" msgstr "ë§í¬ 카드 추가" -#: src/view/com/composer/Composer.tsx:458 +#: src/view/com/composer/Composer.tsx:467 msgid "Add link card:" msgstr "ë§í¬ 카드 추가:" -#: src/components/dialogs/MutedWords.tsx:140 +#: src/components/dialogs/MutedWords.tsx:158 msgid "Add mute word for configured settings" -msgstr "" +msgstr "구성 ì„¤ì •ì— ë®¤íŠ¸ 단어 추가" -#: src/components/dialogs/MutedWords.tsx:74 +#: src/components/dialogs/MutedWords.tsx:87 msgid "Add muted words and tags" -msgstr "" +msgstr "ë®¤íŠ¸í• ë‹¨ì–´ ë° íƒœê·¸ 추가" #: src/view/com/modals/ChangeHandle.tsx:417 msgid "Add the following DNS record to your domain:" msgstr "ë„ë©”ì¸ì— ë‹¤ìŒ DNS ë ˆì½”ë“œë¥¼ 추가하세요:" -#: src/view/com/profile/ProfileHeader.tsx:310 +#: src/view/com/profile/ProfileMenu.tsx:263 +#: src/view/com/profile/ProfileMenu.tsx:266 msgid "Add to Lists" msgstr "ë¦¬ìŠ¤íŠ¸ì— ì¶”ê°€" -#: src/view/com/feeds/FeedSourceCard.tsx:245 -#: src/view/screens/ProfileFeed.tsx:273 +#: src/view/com/feeds/FeedSourceCard.tsx:234 msgid "Add to my feeds" msgstr "ë‚´ í”¼ë“œì— ì¶”ê°€" @@ -207,34 +186,35 @@ msgstr "추가ë¨" msgid "Added to list" msgstr "ë¦¬ìŠ¤íŠ¸ì— ì¶”ê°€ë¨" -#: src/view/com/feeds/FeedSourceCard.tsx:127 +#: src/view/com/feeds/FeedSourceCard.tsx:108 msgid "Added to my feeds" msgstr "ë‚´ í”¼ë“œì— ì¶”ê°€ë¨" #: src/view/screens/PreferencesFollowingFeed.tsx:173 msgid "Adjust the number of likes a reply must have to be shown in your feed." -msgstr "ë‹µê¸€ì´ í”¼ë“œì— í‘œì‹œë˜ê¸° 위해 필요한 좋아요 표시 수를 ì¡°ì •í•©ë‹ˆë‹¤." +msgstr "ë‹µê¸€ì´ í”¼ë“œì— í‘œì‹œë˜ê¸° 위해 필요한 좋아요 수를 ì¡°ì •í•©ë‹ˆë‹¤." #: src/view/com/modals/SelfLabel.tsx:75 msgid "Adult Content" msgstr "ì„±ì¸ ì½˜í…ì¸ " -#: src/view/com/modals/ContentFilteringSettings.tsx:141 -msgid "Adult content can only be enabled via the Web at <0/>." -msgstr "ì„±ì¸ ì½˜í…ì¸ ëŠ” <0/>ì—서 ì›¹ì„ í†µí•´ì„œë§Œ í™œì„±í™”í• ìˆ˜ 있습니다." +#: src/components/moderation/ModerationLabelPref.tsx:102 +msgid "Adult content is disabled." +msgstr "ì„±ì¸ ì½˜í…ì¸ ê°€ 비활성화ë˜ì–´ 있습니다." -#: src/view/screens/Settings/index.tsx:664 +#: src/screens/Moderation/index.tsx:383 +#: src/view/screens/Settings/index.tsx:682 msgid "Advanced" msgstr "ê³ ê¸‰" #: src/view/screens/Feeds.tsx:666 msgid "All the feeds you've saved, right in one place." -msgstr "" +msgstr "ì €ìž¥í•œ ëª¨ë“ í”¼ë“œë¥¼ 한 ê³³ì—서 확ì¸í•˜ì„¸ìš”." #: src/view/com/auth/login/ForgotPasswordForm.tsx:221 #: src/view/com/modals/ChangePassword.tsx:168 msgid "Already have a code?" -msgstr "" +msgstr "ì´ë¯¸ 코드가 있나요?" #: src/view/com/auth/login/ChooseAccountForm.tsx:98 msgid "Already signed in as @{0}" @@ -260,8 +240,12 @@ msgstr "{0}(으)로 ì´ë©”ì¼ì„ 보냈습니다. ì´ ì´ë©”ì¼ì—는 ì•„ëž˜ì— msgid "An email has been sent to your previous address, {0}. It includes a confirmation code which you can enter below." msgstr "ì´ì „ ì£¼ì†Œì¸ {0}(으)로 ì´ë©”ì¼ì„ 보냈습니다. ì´ ì´ë©”ì¼ì—는 ì•„ëž˜ì— ìž…ë ¥í•˜ëŠ” í™•ì¸ ì½”ë“œê°€ í¬í•¨ë˜ì–´ 있습니다." -#: src/view/com/profile/FollowButton.tsx:30 -#: src/view/com/profile/FollowButton.tsx:40 +#: src/lib/moderation/useReportOptions.ts:26 +msgid "An issue not included in these options" +msgstr "ì–´ë–¤ 옵션ì—ë„ í¬í•¨ë˜ì§€ 않는 ë¬¸ì œ" + +#: src/view/com/profile/FollowButton.tsx:35 +#: src/view/com/profile/FollowButton.tsx:45 msgid "An issue occurred, please try again." msgstr "ë¬¸ì œê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤. 다시 시ë„í•´ 주세요." @@ -274,11 +258,15 @@ msgstr "ë°" msgid "Animals" msgstr "ë™ë¬¼" +#: src/lib/moderation/useReportOptions.ts:31 +msgid "Anti-Social Behavior" +msgstr "반사회ì 행위" + #: src/view/screens/LanguageSettings.tsx:95 msgid "App Language" msgstr "앱 언어" -#: src/view/screens/AppPasswords.tsx:228 +#: src/view/screens/AppPasswords.tsx:223 msgid "App password deleted" msgstr "앱 비밀번호 ì‚ì œë¨" @@ -290,57 +278,49 @@ msgstr "앱 비밀번호 ì´ë¦„ì—는 문ìž, 숫ìž, 공백, 대시, 밑줄만 msgid "App Password names must be at least 4 characters long." msgstr "앱 비밀번호 ì´ë¦„ì€ 4ìž ì´ìƒì´ì–´ì•¼ 합니다." -#: src/view/screens/Settings/index.tsx:675 +#: src/view/screens/Settings/index.tsx:693 msgid "App password settings" msgstr "앱 비밀번호 ì„¤ì •" -#: src/view/screens/Settings.tsx:650 -#~ msgid "App passwords" -#~ msgstr "앱 비밀번호" - -#: src/Navigation.tsx:237 -#: src/view/screens/AppPasswords.tsx:187 -#: src/view/screens/Settings/index.tsx:684 +#: src/Navigation.tsx:251 +#: src/view/screens/AppPasswords.tsx:189 +#: src/view/screens/Settings/index.tsx:702 msgid "App Passwords" msgstr "앱 비밀번호" -#: src/view/com/util/forms/PostDropdownBtn.tsx:295 -msgid "Appeal content warning" -msgstr "콘í…ì¸ ê²½ê³ ì´ì˜ì‹ ì²" - -#: src/view/com/modals/AppealLabel.tsx:65 -msgid "Appeal Content Warning" -msgstr "콘í…ì¸ ê²½ê³ ì´ì˜ì‹ ì²" +#: src/components/moderation/LabelsOnMeDialog.tsx:134 +#: src/components/moderation/LabelsOnMeDialog.tsx:137 +msgid "Appeal" +msgstr "ì´ì˜ì‹ ì²" -#: src/view/com/util/moderation/LabelInfo.tsx:52 -msgid "Appeal this decision" -msgstr "ì´ ê²°ì •ì— ì´ì˜ì‹ ì²" +#: src/components/moderation/LabelsOnMeDialog.tsx:202 +msgid "Appeal \"{0}\" label" +msgstr "\"{0}\" ë¼ë²¨ ì´ì˜ì‹ ì²" -#: src/view/com/util/moderation/LabelInfo.tsx:56 -msgid "Appeal this decision." -msgstr "ì´ ê²°ì •ì— ì´ì˜ì‹ ì²í•©ë‹ˆë‹¤." +#: src/components/moderation/LabelsOnMeDialog.tsx:193 +msgid "Appeal submitted." +msgstr "ì´ì˜ì‹ ì² ì œì¶œí•¨" -#: src/view/screens/Settings/index.tsx:466 +#: src/view/screens/Settings/index.tsx:484 msgid "Appearance" msgstr "모양" -#: src/view/screens/AppPasswords.tsx:224 +#: src/view/screens/AppPasswords.tsx:265 msgid "Are you sure you want to delete the app password \"{name}\"?" msgstr "앱 비밀번호 \"{name}\"ì„(를) ì‚ì œí•˜ì‹œê² ìŠµë‹ˆê¹Œ?" -#: src/view/com/composer/Composer.tsx:150 +#: src/view/com/feeds/FeedSourceCard.tsx:280 +msgid "Are you sure you want to remove {0} from your feeds?" +msgstr "피드ì—서 {0}ì„(를) ì œê±°í•˜ì‹œê² ìŠµë‹ˆê¹Œ?" + +#: src/view/com/composer/Composer.tsx:504 msgid "Are you sure you'd like to discard this draft?" msgstr "ì´ ì´ˆì•ˆì„ ì‚ì œí•˜ì‹œê² ìŠµë‹ˆê¹Œ?" -#: src/components/dialogs/MutedWords.tsx:233 -#: src/view/screens/ProfileList.tsx:365 +#: src/components/dialogs/MutedWords.tsx:282 msgid "Are you sure?" msgstr "ì •ë§ì¸ê°€ìš”?" -#: src/view/com/util/forms/PostDropdownBtn.tsx:278 -msgid "Are you sure? This cannot be undone." -msgstr "ì •ë§ì¸ê°€ìš”? ë˜ëŒë¦´ 수 없습니다." - #: src/view/com/composer/select-language/SuggestedLanguage.tsx:60 msgid "Are you writing in <0>{0}</0>?" msgstr "{0}(으)로 ì“°ê³ ìžˆë‚˜ìš”?" @@ -353,21 +333,22 @@ msgstr "ì˜ˆìˆ " msgid "Artistic or non-erotic nudity." msgstr "ì„ ì •ì ì´ì§€ 않거나 ì˜ˆìˆ ì ì¸ ë…¸ì¶œ." +#: src/components/moderation/LabelsOnMeDialog.tsx:247 +#: src/components/moderation/LabelsOnMeDialog.tsx:248 +#: src/screens/Profile/Header/Shell.tsx:97 #: src/view/com/auth/create/CreateAccount.tsx:158 #: src/view/com/auth/login/ChooseAccountForm.tsx:151 #: src/view/com/auth/login/ForgotPasswordForm.tsx:174 #: src/view/com/auth/login/LoginForm.tsx:259 #: src/view/com/auth/login/SetNewPasswordForm.tsx:179 -#: src/view/com/modals/report/InputIssueDetails.tsx:46 -#: src/view/com/post-thread/PostThread.tsx:472 -#: src/view/com/post-thread/PostThread.tsx:522 -#: src/view/com/post-thread/PostThread.tsx:530 -#: src/view/com/profile/ProfileHeader.tsx:649 -#: src/view/com/util/ViewHeader.tsx:81 +#: src/view/com/post-thread/PostThread.tsx:473 +#: src/view/com/post-thread/PostThread.tsx:523 +#: src/view/com/post-thread/PostThread.tsx:531 +#: src/view/com/util/ViewHeader.tsx:87 msgid "Back" msgstr "뒤로" -#: src/view/com/post-thread/PostThread.tsx:480 +#: src/view/com/post-thread/PostThread.tsx:481 msgctxt "action" msgid "Back" msgstr "뒤로" @@ -376,55 +357,61 @@ msgstr "뒤로" msgid "Based on your interest in {interestsText}" msgstr "{interestsText}ì— ëŒ€í•œ 관심사 기반" -#: src/view/screens/Settings/index.tsx:523 +#: src/view/screens/Settings/index.tsx:541 msgid "Basics" msgstr "기본" -#: src/view/com/auth/create/Step1.tsx:250 -#: src/view/com/modals/BirthDateSettings.tsx:73 +#: src/components/dialogs/BirthDateSettings.tsx:101 +#: src/view/com/auth/create/Step1.tsx:227 msgid "Birthday" msgstr "ìƒë…„ì›”ì¼" -#: src/view/screens/Settings/index.tsx:340 +#: src/view/screens/Settings/index.tsx:358 msgid "Birthday:" msgstr "ìƒë…„ì›”ì¼:" -#: src/view/com/profile/ProfileHeader.tsx:239 -#: src/view/com/profile/ProfileHeader.tsx:346 +#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:278 +#: src/view/com/profile/ProfileMenu.tsx:361 +msgid "Block" +msgstr "차단" + +#: src/view/com/profile/ProfileMenu.tsx:300 +#: src/view/com/profile/ProfileMenu.tsx:307 msgid "Block Account" msgstr "ê³„ì • 차단" -#: src/view/screens/ProfileList.tsx:556 +#: src/view/com/profile/ProfileMenu.tsx:344 +msgid "Block Account?" +msgstr "ê³„ì •ì„ ì°¨ë‹¨í•˜ì‹œê² ìŠµë‹ˆê¹Œ?" + +#: src/view/screens/ProfileList.tsx:530 msgid "Block accounts" msgstr "ê³„ì • 차단" -#: src/view/screens/ProfileList.tsx:506 +#: src/view/screens/ProfileList.tsx:478 +#: src/view/screens/ProfileList.tsx:634 msgid "Block list" msgstr "리스트 차단" -#: src/view/screens/ProfileList.tsx:316 +#: src/view/screens/ProfileList.tsx:629 msgid "Block these accounts?" msgstr "ì´ ê³„ì •ë“¤ì„ ì°¨ë‹¨í•˜ì‹œê² ìŠµë‹ˆê¹Œ?" -#: src/view/screens/ProfileList.tsx:320 -msgid "Block this List" -msgstr "ì´ ë¦¬ìŠ¤íŠ¸ 차단" - #: src/view/com/lists/ListCard.tsx:110 -#: src/view/com/util/post-embeds/QuoteEmbed.tsx:61 +#: src/view/com/util/post-embeds/QuoteEmbed.tsx:55 msgid "Blocked" msgstr "차단ë¨" -#: src/view/screens/Moderation.tsx:142 +#: src/screens/Moderation/index.tsx:270 msgid "Blocked accounts" msgstr "차단한 ê³„ì •" -#: src/Navigation.tsx:130 +#: src/Navigation.tsx:134 #: src/view/screens/ModerationBlockedAccounts.tsx:107 msgid "Blocked Accounts" msgstr "차단한 ê³„ì •" -#: src/view/com/profile/ProfileHeader.tsx:241 +#: src/view/com/profile/ProfileMenu.tsx:356 msgid "Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you." msgstr "차단한 ê³„ì •ì€ ë‚´ ìŠ¤ë ˆë“œì— ë‹µê¸€ì„ ë‹¬ê±°ë‚˜ 나를 멘션하거나 기타 다른 ë°©ì‹ìœ¼ë¡œ 나와 ìƒí˜¸ìž‘ìš©í• ìˆ˜ 없습니다." @@ -432,14 +419,22 @@ msgstr "차단한 ê³„ì •ì€ ë‚´ ìŠ¤ë ˆë“œì— ë‹µê¸€ì„ ë‹¬ê±°ë‚˜ 나를 ë©˜ì…˜í• msgid "Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you. You will not see their content and they will be prevented from seeing yours." msgstr "차단한 ê³„ì •ì€ ë‚´ ìŠ¤ë ˆë“œì— ë‹µê¸€ì„ ë‹¬ê±°ë‚˜ 나를 멘션하거나 기타 다른 ë°©ì‹ìœ¼ë¡œ 나와 ìƒí˜¸ìž‘ìš©í• ìˆ˜ 없습니다. 차단한 ê³„ì •ì˜ ì½˜í…ì¸ ë¥¼ ë³¼ 수 없으며 해당 ê³„ì •ë„ ë‚´ 콘í…ì¸ ë¥¼ ë³¼ 수 없게 ë©ë‹ˆë‹¤." -#: src/view/com/post-thread/PostThread.tsx:324 +#: src/view/com/post-thread/PostThread.tsx:325 msgid "Blocked post." msgstr "ì°¨ë‹¨ëœ ê²Œì‹œë¬¼." -#: src/view/screens/ProfileList.tsx:318 +#: src/screens/Profile/Sections/Labels.tsx:171 +msgid "Blocking does not prevent this labeler from placing labels on your account." +msgstr "차단하ë”ë¼ë„ ì´ ë¼ë²¨ëŸ¬ê°€ ë‚´ ê³„ì •ì— ë¼ë²¨ì„ ë¶™ì´ëŠ” ê²ƒì„ ë§‰ì§€ëŠ” 못합니다." + +#: src/view/screens/ProfileList.tsx:631 msgid "Blocking is public. Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you." msgstr "차단 목ë¡ì€ 공개ë©ë‹ˆë‹¤. 차단한 ê³„ì •ì€ ë‚´ ìŠ¤ë ˆë“œì— ë‹µê¸€ì„ ë‹¬ê±°ë‚˜ 나를 멘션하거나 기타 다른 ë°©ì‹ìœ¼ë¡œ 나와 ìƒí˜¸ìž‘ìš©í• ìˆ˜ 없습니다." +#: src/view/com/profile/ProfileMenu.tsx:353 +msgid "Blocking will not prevent labels from being applied on your account, but it will stop this account from replying in your threads or interacting with you." +msgstr "차단하ë”ë¼ë„ ë‚´ ê³„ì •ì— ë¼ë²¨ì´ 붙는 ê²ƒì€ ë§‰ì§€ 못하지만, ì´ ê³„ì •ì´ ë‚´ ìŠ¤ë ˆë“œì— ë‹µê¸€ì„ ë‹¬ê±°ë‚˜ 나와 ìƒí˜¸ìž‘용하는 ê²ƒì€ ì¤‘ì§€ë©ë‹ˆë‹¤." + #: src/view/com/auth/HomeLoggedOutCTA.tsx:93 #: src/view/com/auth/SplashScreen.web.tsx:133 msgid "Blog" @@ -453,7 +448,7 @@ msgstr "Bluesky" #: src/view/com/auth/server-input/index.tsx:150 msgid "Bluesky is an open network where you can choose your hosting provider. Custom hosting is now available in beta for developers." -msgstr "" +msgstr "Bluesky는 호스팅 ì œê³µìžë¥¼ ì„ íƒí• 수 있는 개방형 네트워í¬ìž…니다. 개발ìžë¥¼ 위한 ì‚¬ìš©ìž ì§€ì • í˜¸ìŠ¤íŒ…ì´ ë² íƒ€ ë²„ì „ìœ¼ë¡œ ì œê³µë©ë‹ˆë‹¤." #: src/view/com/auth/onboarding/WelcomeDesktop.tsx:80 #: src/view/com/auth/onboarding/WelcomeMobile.tsx:80 @@ -470,23 +465,23 @@ msgstr "Bluesky는 ì—´ë ¤ 있습니다." msgid "Bluesky is public." msgstr "Bluesky는 공개ì 입니다." -#: src/view/com/modals/Waitlist.tsx:70 -msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon." -msgstr "Bluesky는 ë” ê±´ê°•í•œ 커뮤니티를 구축하기 위해 초대 ë°©ì‹ì„ 사용합니다. 초대해 준 ì‚¬ëžŒì´ ì—†ëŠ” 경우 ëŒ€ê¸°ìž ëª…ë‹¨ì— ë“±ë¡í•˜ë©´ ê³§ 초대를 ë³´ë‚´ê² ìŠµë‹ˆë‹¤." - -#: src/view/screens/Moderation.tsx:245 +#: src/screens/Moderation/index.tsx:539 msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private." msgstr "로그아웃한 사용ìžì—게 ë‚´ 프로필과 ê²Œì‹œë¬¼ì„ í‘œì‹œí•˜ì§€ 않습니다. 다른 앱ì—서는 ì´ ì„¤ì •ì„ ë”°ë¥´ì§€ ì•Šì„ ìˆ˜ 있습니다. ë‚´ ê³„ì •ì„ ë¹„ê³µê°œë¡œ ì „í™˜í•˜ì§€ëŠ” 않습니다." -#: src/view/com/modals/ServerInput.tsx:78 -#~ msgid "Bluesky.Social" -#~ msgstr "Bluesky.Social" +#: src/lib/moderation/useLabelBehaviorDescription.ts:53 +msgid "Blur images" +msgstr "ì´ë¯¸ì§€ í리게" + +#: src/lib/moderation/useLabelBehaviorDescription.ts:51 +msgid "Blur images and filter from feeds" +msgstr "ì´ë¯¸ì§€ í리게 ë° í”¼ë“œì—서 í•„í„°ë§" #: src/screens/Onboarding/index.tsx:33 msgid "Books" msgstr "ì±…" -#: src/view/screens/Settings/index.tsx:859 +#: src/view/screens/Settings/index.tsx:887 msgid "Build version {0} {1}" msgstr "빌드 ë²„ì „ {0} {1}" @@ -495,18 +490,18 @@ msgstr "빌드 ë²„ì „ {0} {1}" msgid "Business" msgstr "비즈니스" -#: src/view/com/modals/ServerInput.tsx:115 -#~ msgid "Button disabled. Input custom domain to proceed." -#~ msgstr "ë²„íŠ¼ì´ ë¹„í™œì„±í™”ë˜ì—ˆìŠµë‹ˆë‹¤. 계ì†í•˜ë ¤ë©´ ì‚¬ìš©ìž ì§€ì • ë„ë©”ì¸ì„ ìž…ë ¥í•˜ì„¸ìš”" - #: src/view/com/profile/ProfileSubpageHeader.tsx:157 msgid "by —" -msgstr "—" +msgstr "— ë‹˜ì´ ë§Œë“¦" #: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:100 msgid "by {0}" msgstr "{0} ë‹˜ì´ ë§Œë“¦" +#: src/components/LabelingServiceCard/index.tsx:57 +msgid "By {0}" +msgstr "{0} ë‹˜ì´ ë§Œë“¦" + #: src/view/com/profile/ProfileSubpageHeader.tsx:161 msgid "by <0/>" msgstr "<0/> ë‹˜ì´ ë§Œë“¦" @@ -515,9 +510,7 @@ msgstr "<0/> ë‹˜ì´ ë§Œë“¦" msgid "by you" msgstr "ë‚´ê°€ 만듦" -#: src/view/com/composer/photos/OpenCameraBtn.tsx:60 -#: src/view/com/util/UserAvatar.tsx:224 -#: src/view/com/util/UserBanner.tsx:40 +#: src/view/com/composer/photos/OpenCameraBtn.tsx:77 msgid "Camera" msgstr "ì¹´ë©”ë¼" @@ -525,9 +518,10 @@ msgstr "ì¹´ë©”ë¼" msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must be at least 4 characters long, but no more than 32 characters long." msgstr "글ìž, 숫ìž, 공백, 대시, 밑줄만 í¬í•¨í• 수 있습니다. 길ì´ëŠ” 4ìž ì´ìƒì´ì–´ì•¼ í•˜ê³ 32ìžë¥¼ 넘지 않아야 합니다." -#: src/components/Prompt.tsx:91 -#: src/view/com/composer/Composer.tsx:307 -#: src/view/com/composer/Composer.tsx:312 +#: src/components/Prompt.tsx:116 +#: src/components/Prompt.tsx:118 +#: src/view/com/composer/Composer.tsx:316 +#: src/view/com/composer/Composer.tsx:321 #: src/view/com/modals/ChangeEmail.tsx:218 #: src/view/com/modals/ChangeEmail.tsx:220 #: src/view/com/modals/ChangePassword.tsx:265 @@ -540,14 +534,11 @@ msgstr "글ìž, 숫ìž, 공백, 대시, 밑줄만 í¬í•¨í• 수 있습니다. ê¸ #: src/view/com/modals/Repost.tsx:87 #: src/view/com/modals/VerifyEmail.tsx:247 #: src/view/com/modals/VerifyEmail.tsx:253 -#: src/view/com/modals/Waitlist.tsx:142 #: src/view/screens/Search/Search.tsx:716 #: src/view/shell/desktop/Search.tsx:238 msgid "Cancel" msgstr "취소" -#: src/view/com/modals/Confirm.tsx:88 -#: src/view/com/modals/Confirm.tsx:91 #: src/view/com/modals/CreateOrEditList.tsx:360 #: src/view/com/modals/DeleteAccount.tsx:156 #: src/view/com/modals/DeleteAccount.tsx:234 @@ -581,21 +572,17 @@ msgstr "게시물 ì¸ìš© 취소" msgid "Cancel search" msgstr "검색 취소" -#: src/view/com/modals/Waitlist.tsx:136 -msgid "Cancel waitlist signup" -msgstr "ëŒ€ê¸°ìž ëª…ë‹¨ ë“±ë¡ ì·¨ì†Œ" - -#: src/view/screens/Settings/index.tsx:334 +#: src/view/screens/Settings/index.tsx:352 msgctxt "action" msgid "Change" msgstr "변경" -#: src/view/screens/Settings/index.tsx:696 +#: src/view/screens/Settings/index.tsx:714 msgid "Change handle" msgstr "핸들 변경" #: src/view/com/modals/ChangeHandle.tsx:161 -#: src/view/screens/Settings/index.tsx:705 +#: src/view/screens/Settings/index.tsx:723 msgid "Change Handle" msgstr "핸들 변경" @@ -603,21 +590,21 @@ msgstr "핸들 변경" msgid "Change my email" msgstr "ë‚´ ì´ë©”ì¼ ë³€ê²½í•˜ê¸°" -#: src/view/screens/Settings/index.tsx:732 +#: src/view/screens/Settings/index.tsx:750 msgid "Change password" -msgstr "" +msgstr "비밀번호 변경" -#: src/view/screens/Settings/index.tsx:741 +#: src/view/screens/Settings/index.tsx:759 msgid "Change Password" -msgstr "" +msgstr "비밀번호 변경" #: src/view/com/composer/select-language/SuggestedLanguage.tsx:73 msgid "Change post language to {0}" msgstr "게시물 언어를 {0}(으)로 변경" -#: src/view/screens/Settings/index.tsx:733 +#: src/view/screens/Settings/index.tsx:751 msgid "Change your Bluesky password" -msgstr "" +msgstr "ë‚´ Bluesky 비밀번호를 변경합니다" #: src/view/com/modals/ChangeEmail.tsx:109 msgid "Change Your Email" @@ -644,7 +631,7 @@ msgstr "ë°›ì€ íŽ¸ì§€í•¨ì—서 ì•„ëž˜ì— ìž…ë ¥í•˜ëŠ” í™•ì¸ ì½”ë“œê°€ í¬í•¨ëœ msgid "Choose \"Everybody\" or \"Nobody\"" msgstr "\"모ë‘\" ë˜ëŠ” \"ì—†ìŒ\"ì„ ì„ íƒí•˜ì„¸ìš”." -#: src/view/screens/Settings/index.tsx:697 +#: src/view/screens/Settings/index.tsx:715 msgid "Choose a new Bluesky username or create" msgstr "새 Bluesky ì‚¬ìš©ìž ì´ë¦„ì„ ì„ íƒí•˜ê±°ë‚˜ ë§Œë“니다" @@ -659,31 +646,31 @@ msgstr "맞춤 피드를 구ë™í• ì•Œê³ ë¦¬ì¦˜ì„ ì„ íƒí•˜ì„¸ìš”." #: src/view/com/auth/onboarding/WelcomeDesktop.tsx:83 #: src/view/com/auth/onboarding/WelcomeMobile.tsx:83 msgid "Choose the algorithms that power your experience with custom feeds." -msgstr "맞춤 피드를 통해 ì‚¬ìš©ìž ê²½í—˜ì„ ê°•í™”í•˜ëŠ” ì•Œê³ ë¦¬ì¦˜ì„ ì„ íƒí•©ë‹ˆë‹¤." +msgstr "맞춤 피드를 통해 ì‚¬ìš©ìž ê²½í—˜ì„ ê°•í™”í•˜ëŠ” ì•Œê³ ë¦¬ì¦˜ì„ ì„ íƒí•˜ì„¸ìš”." #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:103 msgid "Choose your main feeds" msgstr "기본 피드 ì„ íƒ" -#: src/view/com/auth/create/Step1.tsx:219 +#: src/view/com/auth/create/Step1.tsx:196 msgid "Choose your password" msgstr "비밀번호를 ìž…ë ¥í•˜ì„¸ìš”" -#: src/view/screens/Settings/index.tsx:834 -#: src/view/screens/Settings/index.tsx:835 +#: src/view/screens/Settings/index.tsx:862 +#: src/view/screens/Settings/index.tsx:863 msgid "Clear all legacy storage data" msgstr "ëª¨ë“ ë ˆê±°ì‹œ ìŠ¤í† ë¦¬ì§€ ë°ì´í„° 지우기" -#: src/view/screens/Settings/index.tsx:837 +#: src/view/screens/Settings/index.tsx:865 msgid "Clear all legacy storage data (restart after this)" msgstr "ëª¨ë“ ë ˆê±°ì‹œ ìŠ¤í† ë¦¬ì§€ ë°ì´í„° 지우기 (ì´í›„ 다시 시작)" -#: src/view/screens/Settings/index.tsx:846 -#: src/view/screens/Settings/index.tsx:847 +#: src/view/screens/Settings/index.tsx:874 +#: src/view/screens/Settings/index.tsx:875 msgid "Clear all storage data" msgstr "ëª¨ë“ ìŠ¤í† ë¦¬ì§€ ë°ì´í„° 지우기" -#: src/view/screens/Settings/index.tsx:849 +#: src/view/screens/Settings/index.tsx:877 msgid "Clear all storage data (restart after this)" msgstr "ëª¨ë“ ìŠ¤í† ë¦¬ì§€ ë°ì´í„° 지우기 (ì´í›„ 다시 시작)" @@ -696,10 +683,13 @@ msgstr "검색어 지우기" msgid "click here" msgstr "ì´ê³³ì„ í´ë¦" -#: src/components/RichText.tsx:189 -#: src/components/TagMenu/index.web.tsx:125 +#: src/components/TagMenu/index.web.tsx:138 msgid "Click here to open tag menu for {tag}" -msgstr "" +msgstr "ì´ê³³ì„ í´ë¦í•˜ì—¬ {tag}ì˜ íƒœê·¸ 메뉴 열기" + +#: src/components/RichText.tsx:191 +msgid "Click here to open tag menu for #{tag}" +msgstr "ì´ê³³ì„ í´ë¦í•˜ì—¬ #{tag}ì˜ íƒœê·¸ 메뉴 열기" #: src/screens/Onboarding/index.tsx:35 msgid "Climate" @@ -708,22 +698,22 @@ msgstr "기후" #: src/view/com/modals/ChangePassword.tsx:265 #: src/view/com/modals/ChangePassword.tsx:268 msgid "Close" -msgstr "" +msgstr "닫기" -#: src/components/Dialog/index.web.tsx:80 -#: src/components/Dialog/index.web.tsx:194 +#: src/components/Dialog/index.web.tsx:84 +#: src/components/Dialog/index.web.tsx:198 msgid "Close active dialog" -msgstr "활성 대화 ìƒìž 닫기" +msgstr "ì—´ë ¤ 있는 대화 ìƒìž 닫기" #: src/view/com/auth/login/PasswordUpdatedForm.tsx:38 msgid "Close alert" msgstr "알림 닫기" -#: src/view/com/util/BottomSheetCustomBackdrop.tsx:33 +#: src/view/com/util/BottomSheetCustomBackdrop.tsx:36 msgid "Close bottom drawer" msgstr "하단 ì„œëž ë‹«ê¸°" -#: src/view/com/lightbox/ImageViewing/components/ImageDefaultHeader.tsx:26 +#: src/view/com/lightbox/ImageViewing/components/ImageDefaultHeader.tsx:30 msgid "Close image" msgstr "ì´ë¯¸ì§€ 닫기" @@ -731,15 +721,16 @@ msgstr "ì´ë¯¸ì§€ 닫기" msgid "Close image viewer" msgstr "ì´ë¯¸ì§€ ë·°ì–´ 닫기" -#: src/view/shell/index.web.tsx:51 +#: src/view/shell/index.web.tsx:55 msgid "Close navigation footer" msgstr "íƒìƒ‰ 푸터 닫기" -#: src/components/TagMenu/index.tsx:266 +#: src/components/Menu/index.tsx:207 +#: src/components/TagMenu/index.tsx:262 msgid "Close this dialog" -msgstr "" +msgstr "ì´ ëŒ€í™” ìƒìž 닫기" -#: src/view/shell/index.web.tsx:52 +#: src/view/shell/index.web.tsx:56 msgid "Closes bottom navigation bar" msgstr "하단 íƒìƒ‰ 막대를 닫습니다" @@ -747,11 +738,11 @@ msgstr "하단 íƒìƒ‰ 막대를 닫습니다" msgid "Closes password update alert" msgstr "비밀번호 변경 ì•Œë¦¼ì„ ë‹«ìŠµë‹ˆë‹¤" -#: src/view/com/composer/Composer.tsx:309 +#: src/view/com/composer/Composer.tsx:318 msgid "Closes post composer and discards post draft" msgstr "게시물 작성 ìƒìžë¥¼ ë‹«ê³ ê²Œì‹œë¬¼ ì´ˆì•ˆì„ ì‚ì œí•©ë‹ˆë‹¤" -#: src/view/com/lightbox/ImageViewing/components/ImageDefaultHeader.tsx:27 +#: src/view/com/lightbox/ImageViewing/components/ImageDefaultHeader.tsx:31 msgid "Closes viewer for header image" msgstr "í—¤ë” ì´ë¯¸ì§€ 뷰어를 닫습니다" @@ -767,7 +758,7 @@ msgstr "코미디" msgid "Comics" msgstr "만화" -#: src/Navigation.tsx:227 +#: src/Navigation.tsx:241 #: src/view/screens/CommunityGuidelines.tsx:32 msgid "Community Guidelines" msgstr "커뮤니티 ê°€ì´ë“œë¼ì¸" @@ -778,9 +769,9 @@ msgstr "온보딩 완료 후 ê³„ì • 사용 시작" #: src/view/com/auth/create/Step3.tsx:73 msgid "Complete the challenge" -msgstr "" +msgstr "챌린지 완료하기" -#: src/view/com/composer/Composer.tsx:424 +#: src/view/com/composer/Composer.tsx:433 msgid "Compose posts up to {MAX_GRAPHEME_LENGTH} characters in length" msgstr "최대 {MAX_GRAPHEME_LENGTH}ìž ê¸¸ì´ê¹Œì§€ ê¸€ì„ ìž‘ì„±í• ìˆ˜ 있습니다" @@ -788,12 +779,18 @@ msgstr "최대 {MAX_GRAPHEME_LENGTH}ìž ê¸¸ì´ê¹Œì§€ ê¸€ì„ ìž‘ì„±í• ìˆ˜ 있습 msgid "Compose reply" msgstr "답글 작성하기" -#: src/screens/Onboarding/StepModeration/ModerationOption.tsx:67 +#: src/components/moderation/GlobalModerationLabelPref.tsx:69 +#: src/components/moderation/ModerationLabelPref.tsx:128 +#: src/screens/Onboarding/StepModeration/ModerationOption.tsx:81 msgid "Configure content filtering setting for category: {0}" msgstr "{0} ì¹´í…Œê³ ë¦¬ì— ëŒ€í•œ 콘í…ì¸ í•„í„°ë§ ì„¤ì • 구성" -#: src/components/Prompt.tsx:113 -#: src/view/com/modals/AppealLabel.tsx:98 +#: src/components/moderation/ModerationLabelPref.tsx:104 +msgid "Configured in <0>moderation settings</0>." +msgstr "<0>ê²€í† ì„¤ì •</0>ì—서 ì„¤ì •í•©ë‹ˆë‹¤." + +#: src/components/Prompt.tsx:152 +#: src/components/Prompt.tsx:155 #: src/view/com/modals/SelfLabel.tsx:154 #: src/view/com/modals/VerifyEmail.tsx:231 #: src/view/com/modals/VerifyEmail.tsx:233 @@ -802,12 +799,6 @@ msgstr "{0} ì¹´í…Œê³ ë¦¬ì— ëŒ€í•œ 콘í…ì¸ í•„í„°ë§ ì„¤ì • 구성" msgid "Confirm" msgstr "확ì¸" -#: src/view/com/modals/Confirm.tsx:75 -#: src/view/com/modals/Confirm.tsx:78 -msgctxt "action" -msgid "Confirm" -msgstr "확ì¸" - #: src/view/com/modals/ChangeEmail.tsx:193 #: src/view/com/modals/ChangeEmail.tsx:195 msgid "Confirm Change" @@ -821,9 +812,13 @@ msgstr "콘í…ì¸ ì–¸ì–´ ì„¤ì • 확ì¸" msgid "Confirm delete account" msgstr "ê³„ì • ì‚ì œ 확ì¸" -#: src/view/com/modals/ContentFilteringSettings.tsx:156 -msgid "Confirm your age to enable adult content." -msgstr "ì„±ì¸ ì½˜í…ì¸ ë¥¼ ì‚¬ìš©í•˜ë ¤ë©´ 나ì´ë¥¼ 확ì¸í•˜ì„¸ìš”." +#: src/screens/Moderation/index.tsx:304 +msgid "Confirm your age:" +msgstr "나ì´ë¥¼ 확ì¸í•˜ì„¸ìš”:" + +#: src/screens/Moderation/index.tsx:295 +msgid "Confirm your birthdate" +msgstr "ìƒë…„ì›”ì¼ í™•ì¸" #: src/view/com/modals/ChangeEmail.tsx:157 #: src/view/com/modals/DeleteAccount.tsx:182 @@ -831,10 +826,6 @@ msgstr "ì„±ì¸ ì½˜í…ì¸ ë¥¼ ì‚¬ìš©í•˜ë ¤ë©´ 나ì´ë¥¼ 확ì¸í•˜ì„¸ìš”." msgid "Confirmation code" msgstr "í™•ì¸ ì½”ë“œ" -#: src/view/com/modals/Waitlist.tsx:120 -msgid "Confirms signing up {email} to the waitlist" -msgstr "{email}ì„(를) ëŒ€ê¸°ìž ëª…ë‹¨ì— ë“±ë¡í•©ë‹ˆë‹¤" - #: src/view/com/auth/create/CreateAccount.tsx:193 #: src/view/com/auth/login/LoginForm.tsx:278 msgid "Connecting..." @@ -844,25 +835,32 @@ msgstr "ì—°ê²° 중…" msgid "Contact support" msgstr "ì§€ì›ì— ì—°ë½í•˜ê¸°" -#: src/view/screens/Moderation.tsx:83 -msgid "Content filtering" -msgstr "콘í…ì¸ í•„í„°ë§" +#: src/components/moderation/LabelsOnMe.tsx:42 +msgid "content" +msgstr "콘í…ì¸ " -#: src/view/com/modals/ContentFilteringSettings.tsx:44 -msgid "Content Filtering" -msgstr "콘í…ì¸ í•„í„°ë§" +#: src/lib/moderation/useGlobalLabelStrings.ts:18 +msgid "Content Blocked" +msgstr "콘í…ì¸ ì°¨ë‹¨ë¨" + +#: src/screens/Moderation/index.tsx:288 +msgid "Content filters" +msgstr "콘í…ì¸ í•„í„°" #: src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx:74 #: src/view/screens/LanguageSettings.tsx:278 msgid "Content Languages" msgstr "콘í…ì¸ ì–¸ì–´" -#: src/view/com/modals/ModerationDetails.tsx:65 +#: src/components/moderation/ModerationDetailsDialog.tsx:76 +#: src/lib/moderation/useModerationCauseDescription.ts:75 msgid "Content Not Available" msgstr "콘í…ì¸ ë¥¼ ì‚¬ìš©í• ìˆ˜ ì—†ìŒ" -#: src/view/com/modals/ModerationDetails.tsx:33 -#: src/view/com/util/moderation/ScreenHider.tsx:78 +#: src/components/moderation/ModerationDetailsDialog.tsx:47 +#: src/components/moderation/ScreenHider.tsx:99 +#: src/lib/moderation/useGlobalLabelStrings.ts:22 +#: src/lib/moderation/useModerationCauseDescription.ts:38 msgid "Content Warning" msgstr "콘í…ì¸ ê²½ê³ " @@ -870,10 +868,14 @@ msgstr "콘í…ì¸ ê²½ê³ " msgid "Content warnings" msgstr "콘í…ì¸ ê²½ê³ " +#: src/components/Menu/index.web.tsx:84 +msgid "Context menu backdrop, click to close the menu." +msgstr "컨í…스트 메뉴 ë°°ê²½ì„ í´ë¦í•˜ì—¬ 메뉴를 닫습니다." + #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:170 #: src/screens/Onboarding/StepFollowingFeed.tsx:153 #: src/screens/Onboarding/StepInterests/index.tsx:248 -#: src/screens/Onboarding/StepModeration/index.tsx:118 +#: src/screens/Onboarding/StepModeration/index.tsx:102 #: src/screens/Onboarding/StepTopicalFeeds.tsx:114 #: src/view/com/auth/onboarding/RecommendedFeeds.tsx:148 #: src/view/com/auth/onboarding/RecommendedFollows.tsx:209 @@ -882,7 +884,7 @@ msgstr "계ì†" #: src/screens/Onboarding/StepFollowingFeed.tsx:150 #: src/screens/Onboarding/StepInterests/index.tsx:245 -#: src/screens/Onboarding/StepModeration/index.tsx:115 +#: src/screens/Onboarding/StepModeration/index.tsx:99 #: src/screens/Onboarding/StepTopicalFeeds.tsx:111 msgid "Continue to next step" msgstr "ë‹¤ìŒ ë‹¨ê³„ë¡œ 계ì†í•˜ê¸°" @@ -904,13 +906,13 @@ msgstr "요리" msgid "Copied" msgstr "복사ë¨" -#: src/view/screens/Settings/index.tsx:241 +#: src/view/screens/Settings/index.tsx:247 msgid "Copied build version to clipboard" msgstr "빌드 ë²„ì „ í´ë¦½ë³´ë“œì— 복사ë¨" #: src/view/com/modals/AddAppPasswords.tsx:76 #: src/view/com/modals/InviteCodes.tsx:152 -#: src/view/com/util/forms/PostDropdownBtn.tsx:143 +#: src/view/com/util/forms/PostDropdownBtn.tsx:158 msgid "Copied to clipboard" msgstr "í´ë¦½ë³´ë“œì— 복사ë¨" @@ -922,46 +924,40 @@ msgstr "앱 비밀번호를 복사합니다" msgid "Copy" msgstr "복사" -#: src/view/screens/ProfileList.tsx:418 +#: src/view/screens/ProfileList.tsx:388 msgid "Copy link to list" msgstr "리스트 ë§í¬ 복사" -#: src/view/com/util/forms/PostDropdownBtn.tsx:184 +#: src/view/com/util/forms/PostDropdownBtn.tsx:228 +#: src/view/com/util/forms/PostDropdownBtn.tsx:237 msgid "Copy link to post" msgstr "게시물 ë§í¬ 복사" -#: src/view/com/profile/ProfileHeader.tsx:295 -msgid "Copy link to profile" -msgstr "프로필 ë§í¬ 복사" - -#: src/view/com/util/forms/PostDropdownBtn.tsx:170 +#: src/view/com/util/forms/PostDropdownBtn.tsx:220 +#: src/view/com/util/forms/PostDropdownBtn.tsx:222 msgid "Copy post text" msgstr "게시물 í…스트 복사" -#: src/Navigation.tsx:232 +#: src/Navigation.tsx:246 #: src/view/screens/CopyrightPolicy.tsx:29 msgid "Copyright Policy" msgstr "ì €ìž‘ê¶Œ ì •ì±…" -#: src/view/screens/ProfileFeed.tsx:97 +#: src/view/screens/ProfileFeed.tsx:102 msgid "Could not load feed" msgstr "피드를 불러올 수 없습니다" -#: src/view/screens/ProfileList.tsx:888 +#: src/view/screens/ProfileList.tsx:907 msgid "Could not load list" msgstr "리스트를 불러올 수 없습니다" -#: src/view/com/auth/create/Step2.tsx:91 -#~ msgid "Country" -#~ msgstr "êµê°€" - #: src/view/com/auth/HomeLoggedOutCTA.tsx:62 #: src/view/com/auth/SplashScreen.tsx:71 #: src/view/com/auth/SplashScreen.web.tsx:81 msgid "Create a new account" msgstr "새 ê³„ì • 만들기" -#: src/view/screens/Settings/index.tsx:384 +#: src/view/screens/Settings/index.tsx:402 msgid "Create a new Bluesky account" msgstr "새 Bluesky ê³„ì •ì„ ë§Œë“니다" @@ -978,19 +974,15 @@ msgstr "앱 비밀번호 만들기" msgid "Create new account" msgstr "새 ê³„ì • 만들기" -#: src/view/screens/AppPasswords.tsx:249 -msgid "Created {0}" -msgstr "{0} ìƒì„±ë¨" - -#: src/view/screens/ProfileFeed.tsx:616 -msgid "Created by <0/>" -msgstr "<0/> ë‹˜ì´ ë§Œë“¦" +#: src/components/ReportDialog/SelectReportOptionView.tsx:93 +msgid "Create report for {0}" +msgstr "{0}ì— ëŒ€í•œ ì‹ ê³ ìž‘ì„±í•˜ê¸°" -#: src/view/screens/ProfileFeed.tsx:614 -msgid "Created by you" -msgstr "ë‚´ê°€ 만듦" +#: src/view/screens/AppPasswords.tsx:246 +msgid "Created {0}" +msgstr "{0}ì— ìƒì„±ë¨" -#: src/view/com/composer/Composer.tsx:455 +#: src/view/com/composer/Composer.tsx:464 msgid "Creates a card with a thumbnail. The card links to {url}" msgstr "미리보기 ì´ë¯¸ì§€ê°€ 있는 카드를 ë§Œë“니다. 카드가 {url}(으)로 ì—°ê²°ë©ë‹ˆë‹¤" @@ -1001,7 +993,7 @@ msgstr "문화" #: src/view/com/auth/server-input/index.tsx:95 #: src/view/com/auth/server-input/index.tsx:96 msgid "Custom" -msgstr "" +msgstr "ì‚¬ìš©ìž ì§€ì •" #: src/view/com/modals/ChangeHandle.tsx:389 msgid "Custom domain" @@ -1016,12 +1008,8 @@ msgstr "커뮤니티ì—서 구축한 맞춤 피드는 새로운 ê²½í—˜ì„ ì œê³µ msgid "Customize media from external sites." msgstr "외부 사ì´íЏ 미디어를 ì‚¬ìš©ìž ì§€ì •í•©ë‹ˆë‹¤." -#: src/view/screens/Settings.tsx:687 -#~ msgid "Danger Zone" -#~ msgstr "위험 구ì—" - -#: src/view/screens/Settings/index.tsx:485 -#: src/view/screens/Settings/index.tsx:511 +#: src/view/screens/Settings/index.tsx:503 +#: src/view/screens/Settings/index.tsx:529 msgid "Dark" msgstr "ì–´ë‘움" @@ -1029,15 +1017,25 @@ msgstr "ì–´ë‘움" msgid "Dark mode" msgstr "ì–´ë‘ìš´ 모드" -#: src/view/screens/Settings/index.tsx:498 +#: src/view/screens/Settings/index.tsx:516 msgid "Dark Theme" -msgstr "" +msgstr "ì–´ë‘ìš´ 테마" + +#: src/view/screens/Settings/index.tsx:835 +msgid "Debug Moderation" +msgstr "ê²€í† ë””ë²„ê·¸" #: src/view/screens/Debug.tsx:83 msgid "Debug panel" msgstr "디버그 패ë„" -#: src/view/screens/Settings/index.tsx:772 +#: src/view/com/util/forms/PostDropdownBtn.tsx:319 +#: src/view/screens/AppPasswords.tsx:268 +#: src/view/screens/ProfileList.tsx:613 +msgid "Delete" +msgstr "ì‚ì œ" + +#: src/view/screens/Settings/index.tsx:790 msgid "Delete account" msgstr "ê³„ì • ì‚ì œ" @@ -1045,13 +1043,15 @@ msgstr "ê³„ì • ì‚ì œ" msgid "Delete Account" msgstr "ê³„ì • ì‚ì œ" -#: src/view/screens/AppPasswords.tsx:222 -#: src/view/screens/AppPasswords.tsx:242 +#: src/view/screens/AppPasswords.tsx:239 msgid "Delete app password" msgstr "앱 비밀번호 ì‚ì œ" -#: src/view/screens/ProfileList.tsx:364 -#: src/view/screens/ProfileList.tsx:445 +#: src/view/screens/AppPasswords.tsx:263 +msgid "Delete app password?" +msgstr "앱 비밀번호를 ì‚ì œí•˜ì‹œê² ìŠµë‹ˆê¹Œ?" + +#: src/view/screens/ProfileList.tsx:415 msgid "Delete List" msgstr "리스트 ì‚ì œ" @@ -1059,27 +1059,28 @@ msgstr "리스트 ì‚ì œ" msgid "Delete my account" msgstr "ë‚´ ê³„ì • ì‚ì œ" -#: src/view/screens/Settings.tsx:706 -#~ msgid "Delete my account…" -#~ msgstr "ë‚´ ê³„ì • ì‚ì œâ€¦" - -#: src/view/screens/Settings/index.tsx:784 +#: src/view/screens/Settings/index.tsx:802 msgid "Delete My Account…" -msgstr "" +msgstr "ë‚´ ê³„ì • ì‚ì œâ€¦" -#: src/view/com/util/forms/PostDropdownBtn.tsx:273 +#: src/view/com/util/forms/PostDropdownBtn.tsx:302 +#: src/view/com/util/forms/PostDropdownBtn.tsx:304 msgid "Delete post" msgstr "게시물 ì‚ì œ" -#: src/view/com/util/forms/PostDropdownBtn.tsx:277 +#: src/view/screens/ProfileList.tsx:608 +msgid "Delete this list?" +msgstr "ì´ ë¦¬ìŠ¤íŠ¸ë¥¼ ì‚ì œí•˜ì‹œê² ìŠµë‹ˆê¹Œ?" + +#: src/view/com/util/forms/PostDropdownBtn.tsx:314 msgid "Delete this post?" msgstr "ì´ ê²Œì‹œë¬¼ì„ ì‚ì œí•˜ì‹œê² ìŠµë‹ˆê¹Œ?" -#: src/view/com/util/post-embeds/QuoteEmbed.tsx:70 +#: src/view/com/util/post-embeds/QuoteEmbed.tsx:64 msgid "Deleted" msgstr "ì‚ì œë¨" -#: src/view/com/post-thread/PostThread.tsx:316 +#: src/view/com/post-thread/PostThread.tsx:317 msgid "Deleted post." msgstr "ì‚ì œëœ ê²Œì‹œë¬¼." @@ -1090,27 +1091,31 @@ msgstr "ì‚ì œëœ ê²Œì‹œë¬¼." msgid "Description" msgstr "설명" -#: src/view/screens/Settings.tsx:760 -#~ msgid "Developer Tools" -#~ msgstr "ê°œë°œìž ë„구" - -#: src/view/com/composer/Composer.tsx:218 +#: src/view/com/composer/Composer.tsx:217 msgid "Did you want to say anything?" msgstr "í•˜ê³ ì‹¶ì€ ë§ì´ 있나요?" -#: src/view/screens/Settings/index.tsx:504 +#: src/view/screens/Settings/index.tsx:522 msgid "Dim" -msgstr "" +msgstr "어둑함" + +#: src/lib/moderation/useLabelBehaviorDescription.ts:32 +#: src/lib/moderation/useLabelBehaviorDescription.ts:42 +#: src/lib/moderation/useLabelBehaviorDescription.ts:68 +#: src/screens/Moderation/index.tsx:347 +msgid "Disabled" +msgstr "비활성화ë¨" -#: src/view/com/composer/Composer.tsx:151 +#: src/view/com/composer/Composer.tsx:506 msgid "Discard" msgstr "ì‚ì œ" -#: src/view/com/composer/Composer.tsx:145 -msgid "Discard draft" +#: src/view/com/composer/Composer.tsx:503 +msgid "Discard draft?" msgstr "초안 ì‚ì œ" -#: src/view/screens/Moderation.tsx:226 +#: src/screens/Moderation/index.tsx:524 +#: src/screens/Moderation/index.tsx:528 msgid "Discourage apps from showing my account to logged-out users" msgstr "ì•±ì´ ë¡œê·¸ì•„ì›ƒí•œ 사용ìžì—게 ë‚´ ê³„ì •ì„ í‘œì‹œí•˜ì§€ 않ë„ë¡ ì„¤ì •í•˜ê¸°" @@ -1119,13 +1124,9 @@ msgstr "ì•±ì´ ë¡œê·¸ì•„ì›ƒí•œ 사용ìžì—게 ë‚´ ê³„ì •ì„ í‘œì‹œí•˜ì§€ ì•Šë„ msgid "Discover new custom feeds" msgstr "새로운 맞춤 피드 찾아보기" -#: src/view/screens/Feeds.tsx:473 -#~ msgid "Discover new feeds" -#~ msgstr "새 피드 발견하기" - #: src/view/screens/Feeds.tsx:689 msgid "Discover New Feeds" -msgstr "" +msgstr "새 피드 발견하기" #: src/view/com/modals/EditProfile.tsx:192 msgid "Display name" @@ -1135,33 +1136,20 @@ msgstr "표시 ì´ë¦„" msgid "Display Name" msgstr "표시 ì´ë¦„" +#: src/lib/moderation/useGlobalLabelStrings.ts:39 +msgid "Does not include nudity." +msgstr "ë…¸ì¶œì„ í¬í•¨í•˜ì§€ 않ìŒ." + #: src/view/com/modals/ChangeHandle.tsx:487 msgid "Domain verified!" msgstr "ë„ë©”ì¸ì„ 확ì¸í–ˆìŠµë‹ˆë‹¤." -#: src/view/com/auth/create/Step1.tsx:170 -msgid "Don't have an invite code?" -msgstr "초대 코드가 없나요?" - -#: src/view/com/auth/onboarding/RecommendedFollows.tsx:86 -#: src/view/com/modals/EditImage.tsx:333 -#: src/view/com/modals/ListAddRemoveUsers.tsx:144 -#: src/view/com/modals/SelfLabel.tsx:157 -#: src/view/com/modals/Threadgate.tsx:129 -#: src/view/com/modals/Threadgate.tsx:132 -#: src/view/com/modals/UserAddRemoveLists.tsx:95 -#: src/view/com/modals/UserAddRemoveLists.tsx:98 -#: src/view/screens/PreferencesThreads.tsx:162 -msgctxt "action" -msgid "Done" -msgstr "완료" - +#: src/components/dialogs/BirthDateSettings.tsx:112 +#: src/components/dialogs/BirthDateSettings.tsx:118 #: src/view/com/auth/server-input/index.tsx:165 #: src/view/com/auth/server-input/index.tsx:166 #: src/view/com/modals/AddAppPasswords.tsx:226 #: src/view/com/modals/AltImage.tsx:139 -#: src/view/com/modals/ContentFilteringSettings.tsx:88 -#: src/view/com/modals/ContentFilteringSettings.tsx:96 #: src/view/com/modals/crop-image/CropImage.web.tsx:152 #: src/view/com/modals/InviteCodes.tsx:80 #: src/view/com/modals/InviteCodes.tsx:123 @@ -1172,6 +1160,19 @@ msgstr "완료" msgid "Done" msgstr "완료" +#: src/view/com/auth/onboarding/RecommendedFollows.tsx:86 +#: src/view/com/modals/EditImage.tsx:333 +#: src/view/com/modals/ListAddRemoveUsers.tsx:144 +#: src/view/com/modals/SelfLabel.tsx:157 +#: src/view/com/modals/Threadgate.tsx:129 +#: src/view/com/modals/Threadgate.tsx:132 +#: src/view/com/modals/UserAddRemoveLists.tsx:95 +#: src/view/com/modals/UserAddRemoveLists.tsx:98 +#: src/view/screens/PreferencesThreads.tsx:162 +msgctxt "action" +msgid "Done" +msgstr "완료" + #: src/view/com/modals/lang-settings/ConfirmLanguagesButton.tsx:42 msgid "Done{extraText}" msgstr "완료{extraText}" @@ -1180,20 +1181,20 @@ msgstr "완료{extraText}" msgid "Double tap to sign in" msgstr "ë‘ ë²ˆ íƒí•˜ì—¬ 로그ì¸í•©ë‹ˆë‹¤" -#: src/view/screens/Settings/index.tsx:755 +#: src/view/screens/Settings/index.tsx:773 msgid "Download Bluesky account data (repository)" -msgstr "" +msgstr "Bluesky ê³„ì • ë°ì´í„°ë¥¼ 다운로드합니다 (ì €ìž¥ì†Œ)" #: src/view/screens/Settings/ExportCarDialog.tsx:59 #: src/view/screens/Settings/ExportCarDialog.tsx:63 msgid "Download CAR file" -msgstr "" +msgstr "CAR íŒŒì¼ ë‹¤ìš´ë¡œë“œ" #: src/view/com/composer/text-input/TextInput.web.tsx:249 msgid "Drop to add images" msgstr "드ë¡í•˜ì—¬ ì´ë¯¸ì§€ 추가" -#: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:111 +#: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:116 msgid "Due to Apple policies, adult content can only be enabled on the web after completing sign up." msgstr "Apple ì •ì±…ìœ¼ë¡œ ì¸í•´ ì„±ì¸ ì½˜í…ì¸ ëŠ” ê°€ìž…ì„ ì™„ë£Œí•œ í›„ì— ì›¹ì—서만 사용 ì„¤ì •í• ìˆ˜ 있습니다." @@ -1205,6 +1206,10 @@ msgstr "예: 앨리스 ë¡œë²„ì¸ " msgid "e.g. Artist, dog-lover, and avid reader." msgstr "예: ì˜ˆìˆ ê°€, ê°œ ì• í˜¸ê°€, ë…서광." +#: src/lib/moderation/useGlobalLabelStrings.ts:43 +msgid "E.g. artistic nudes." +msgstr "예: ì˜ˆìˆ ì ì¸ ë…¸ì¶œ." + #: src/view/com/modals/CreateOrEditList.tsx:283 msgid "e.g. Great Posters" msgstr "예: ë©‹ì§„ í¬ìŠ¤í„°" @@ -1230,12 +1235,17 @@ msgctxt "action" msgid "Edit" msgstr "편집" +#: src/view/com/util/UserAvatar.tsx:295 +#: src/view/com/util/UserBanner.tsx:85 +msgid "Edit avatar" +msgstr "아바타 편집" + #: src/view/com/composer/photos/Gallery.tsx:144 #: src/view/com/modals/EditImage.tsx:207 msgid "Edit image" msgstr "ì´ë¯¸ì§€ 편집" -#: src/view/screens/ProfileList.tsx:433 +#: src/view/screens/ProfileList.tsx:403 msgid "Edit list details" msgstr "리스트 세부 ì •ë³´ 편집" @@ -1243,7 +1253,7 @@ msgstr "리스트 세부 ì •ë³´ 편집" msgid "Edit Moderation List" msgstr "ê²€í† ë¦¬ìŠ¤íŠ¸ 편집" -#: src/Navigation.tsx:242 +#: src/Navigation.tsx:256 #: src/view/screens/Feeds.tsx:434 #: src/view/screens/SavedFeeds.tsx:84 msgid "Edit My Feeds" @@ -1253,15 +1263,17 @@ msgstr "ë‚´ 피드 편집" msgid "Edit my profile" msgstr "ë‚´ 프로필 편집" -#: src/view/com/profile/ProfileHeader.tsx:418 +#: src/screens/Profile/Header/ProfileHeaderLabeler.tsx:172 +#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:161 msgid "Edit profile" msgstr "프로필 편집" -#: src/view/com/profile/ProfileHeader.tsx:423 +#: src/screens/Profile/Header/ProfileHeaderLabeler.tsx:175 +#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:164 msgid "Edit Profile" msgstr "프로필 편집" -#: src/view/com/home/HomeHeaderLayout.web.tsx:59 +#: src/view/com/home/HomeHeaderLayout.web.tsx:62 #: src/view/screens/Feeds.tsx:355 msgid "Edit Saved Feeds" msgstr "ì €ìž¥ëœ í”¼ë“œ 편집" @@ -1282,14 +1294,13 @@ msgstr "ë‚´ 프로필 설명 편집" msgid "Education" msgstr "êµìœ¡" -#: src/view/com/auth/create/Step1.tsx:199 +#: src/view/com/auth/create/Step1.tsx:176 #: src/view/com/auth/login/ForgotPasswordForm.tsx:156 #: src/view/com/modals/ChangeEmail.tsx:141 -#: src/view/com/modals/Waitlist.tsx:88 msgid "Email" msgstr "ì´ë©”ì¼" -#: src/view/com/auth/create/Step1.tsx:190 +#: src/view/com/auth/create/Step1.tsx:167 #: src/view/com/auth/login/ForgotPasswordForm.tsx:147 msgid "Email address" msgstr "ì´ë©”ì¼ ì£¼ì†Œ" @@ -1307,7 +1318,7 @@ msgstr "ì´ë©”ì¼ ë³€ê²½ë¨" msgid "Email verified" msgstr "ì´ë©”ì¼ í™•ì¸ë¨" -#: src/view/screens/Settings/index.tsx:312 +#: src/view/screens/Settings/index.tsx:330 msgid "Email:" msgstr "ì´ë©”ì¼:" @@ -1315,12 +1326,12 @@ msgstr "ì´ë©”ì¼:" msgid "Enable {0} only" msgstr "{0}ë§Œ 사용" -#: src/view/com/modals/ContentFilteringSettings.tsx:167 -msgid "Enable Adult Content" +#: src/screens/Moderation/index.tsx:335 +msgid "Enable adult content" msgstr "ì„±ì¸ ì½˜í…ì¸ í™œì„±í™”" -#: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:76 -#: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:77 +#: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:78 +#: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:79 msgid "Enable adult content in your feeds" msgstr "피드ì—서 ì„±ì¸ ì½˜í…ì¸ ì‚¬ìš©" @@ -1336,7 +1347,11 @@ msgstr "미디어 í”Œë ˆì´ì–´ë¥¼ ì‚¬ìš©í• ì™¸ë¶€ 사ì´íЏ" msgid "Enable this setting to only see replies between people you follow." msgstr "ë‚´ê°€ 팔로우하는 사람들 ê°„ì˜ ë‹µê¸€ë§Œ 표시합니다." -#: src/view/screens/Profile.tsx:455 +#: src/screens/Moderation/index.tsx:345 +msgid "Enabled" +msgstr "활성화ë¨" + +#: src/screens/Profile/Sections/Feed.tsx:84 msgid "End of feed" msgstr "피드 ë" @@ -1344,10 +1359,10 @@ msgstr "피드 ë" msgid "Enter a name for this App Password" msgstr "ì´ ì•± ë¹„ë°€ë²ˆí˜¸ì˜ ì´ë¦„ì„ ìž…ë ¥í•˜ì„¸ìš”" -#: src/components/dialogs/MutedWords.tsx:87 -#: src/components/dialogs/MutedWords.tsx:88 +#: src/components/dialogs/MutedWords.tsx:100 +#: src/components/dialogs/MutedWords.tsx:101 msgid "Enter a word or tag" -msgstr "" +msgstr "단어 ë˜ëŠ” 태그 ìž…ë ¥" #: src/view/com/modals/VerifyEmail.tsx:105 msgid "Enter Confirmation Code" @@ -1355,7 +1370,7 @@ msgstr "í™•ì¸ ì½”ë“œ ìž…ë ¥" #: src/view/com/modals/ChangePassword.tsx:151 msgid "Enter the code you received to change your password." -msgstr "" +msgstr "비밀번호를 ë³€ê²½í•˜ë ¤ë©´ ë°›ì€ ì½”ë“œë¥¼ ìž…ë ¥í•˜ì„¸ìš”." #: src/view/com/modals/ChangeHandle.tsx:371 msgid "Enter the domain you want to use" @@ -1363,18 +1378,14 @@ msgstr "ì‚¬ìš©í• ë„ë©”ì¸ ìž…ë ¥" #: src/view/com/auth/login/ForgotPasswordForm.tsx:107 msgid "Enter the email you used to create your account. We'll send you a \"reset code\" so you can set a new password." -msgstr "ê³„ì •ì„ ë§Œë“¤ 때 사용한 ì´ë©”ì¼ì„ ìž…ë ¥í•©ë‹ˆë‹¤. 새 비밀번호를 ì„¤ì •í• ìˆ˜ 있ë„ë¡ \"ìž¬ì„¤ì • 코드\"를 보내드립니다." +msgstr "ê³„ì •ì„ ë§Œë“¤ 때 사용한 ì´ë©”ì¼ì„ ìž…ë ¥í•˜ì„¸ìš”. 새 비밀번호를 ì„¤ì •í• ìˆ˜ 있ë„ë¡ \"ìž¬ì„¤ì • 코드\"를 보내드립니다." -#: src/view/com/auth/create/Step1.tsx:251 -#: src/view/com/modals/BirthDateSettings.tsx:74 +#: src/components/dialogs/BirthDateSettings.tsx:102 +#: src/view/com/auth/create/Step1.tsx:228 msgid "Enter your birth date" msgstr "ìƒë…„ì›”ì¼ì„ ìž…ë ¥í•˜ì„¸ìš”" -#: src/view/com/modals/Waitlist.tsx:78 -msgid "Enter your email" -msgstr "ì´ë©”ì¼ì„ ìž…ë ¥í•˜ì„¸ìš”" - -#: src/view/com/auth/create/Step1.tsx:195 +#: src/view/com/auth/create/Step1.tsx:172 msgid "Enter your email address" msgstr "ì´ë©”ì¼ ì£¼ì†Œë¥¼ ìž…ë ¥í•˜ì„¸ìš”" @@ -1386,17 +1397,13 @@ msgstr "새 ì´ë©”ì¼ì„ ìž…ë ¥í•˜ì„¸ìš”" msgid "Enter your new email address below." msgstr "ì•„ëž˜ì— ìƒˆ ì´ë©”ì¼ ì£¼ì†Œë¥¼ ìž…ë ¥í•˜ì„¸ìš”." -#: src/view/com/auth/create/Step2.tsx:188 -#~ msgid "Enter your phone number" -#~ msgstr "ì „í™”ë²ˆí˜¸ë¥¼ ìž…ë ¥í•˜ì„¸ìš”" - #: src/view/com/auth/login/Login.tsx:99 msgid "Enter your username and password" msgstr "ì‚¬ìš©ìž ì´ë¦„ ë° ë¹„ë°€ë²ˆí˜¸ ìž…ë ¥" #: src/view/com/auth/create/Step3.tsx:67 msgid "Error receiving captcha response." -msgstr "" +msgstr "캡차 ì‘ë‹µì„ ìˆ˜ì‹ í•˜ëŠ” ë™ì•ˆ 오류가 ë°œìƒí–ˆìŠµë‹ˆë‹¤." #: src/view/screens/Search/Search.tsx:110 msgid "Error:" @@ -1406,6 +1413,10 @@ msgstr "오류:" msgid "Everybody" msgstr "모ë‘" +#: src/lib/moderation/useReportOptions.ts:66 +msgid "Excessive mentions or replies" +msgstr "ê³¼ë„한 멘션 ë˜ëŠ” 답글" + #: src/view/com/modals/ChangeHandle.tsx:150 msgid "Exits handle change process" msgstr "핸들 변경 프로세스를 종료합니다" @@ -1419,10 +1430,6 @@ msgstr "ì´ë¯¸ì§€ 보기를 종료합니다" msgid "Exits inputting search query" msgstr "검색어 ìž…ë ¥ì„ ì¢…ë£Œí•©ë‹ˆë‹¤" -#: src/view/com/modals/Waitlist.tsx:138 -msgid "Exits signing up for waitlist with {email}" -msgstr "{email}ì„(를) ëŒ€ê¸°ìž ëª…ë‹¨ì— ë“±ë¡í•˜ëŠ” ê²ƒì„ ì¢…ë£Œí•©ë‹ˆë‹¤" - #: src/view/com/lightbox/Lightbox.web.tsx:163 msgid "Expand alt text" msgstr "대체 í…스트 확장" @@ -1432,14 +1439,22 @@ msgstr "대체 í…스트 확장" msgid "Expand or collapse the full post you are replying to" msgstr "ë‹µê¸€ì„ ë‹¬ê³ ìžˆëŠ” ì „ì²´ ê²Œì‹œë¬¼ì„ íŽ¼ì¹˜ê±°ë‚˜ ì ‘ìŠµë‹ˆë‹¤" -#: src/view/screens/Settings/index.tsx:753 +#: src/lib/moderation/useGlobalLabelStrings.ts:47 +msgid "Explicit or potentially disturbing media." +msgstr "노골ì ì´ê±°ë‚˜ 불쾌ê°ì„ 줄 수 있는 미디어." + +#: src/lib/moderation/useGlobalLabelStrings.ts:35 +msgid "Explicit sexual images." +msgstr "노골ì ì¸ ì„±ì ì´ë¯¸ì§€." + +#: src/view/screens/Settings/index.tsx:771 msgid "Export my data" -msgstr "" +msgstr "ë‚´ ë°ì´í„° 내보내기" #: src/view/screens/Settings/ExportCarDialog.tsx:44 -#: src/view/screens/Settings/index.tsx:764 +#: src/view/screens/Settings/index.tsx:782 msgid "Export My Data" -msgstr "" +msgstr "ë‚´ ë°ì´í„° 내보내기" #: src/view/com/modals/EmbedConsent.tsx:64 msgid "External Media" @@ -1450,13 +1465,13 @@ msgstr "외부 미디어" msgid "External media may allow websites to collect information about you and your device. No information is sent or requested until you press the \"play\" button." msgstr "외부 미디어는 웹사ì´íŠ¸ê°€ 나와 ë‚´ ê¸°ê¸°ì— ëŒ€í•œ ì •ë³´ë¥¼ 수집하ë„ë¡ í• ìˆ˜ 있습니다. \"재ìƒ\" ë²„íŠ¼ì„ ëˆ„ë¥´ê¸° ì „ê¹Œì§€ëŠ” ì–´ë– í•œ ì •ë³´ë„ ì „ì†¡ë˜ê±°ë‚˜ ìš”ì²ë˜ì§€ 않습니다." -#: src/Navigation.tsx:261 +#: src/Navigation.tsx:275 #: src/view/screens/PreferencesExternalEmbeds.tsx:52 -#: src/view/screens/Settings/index.tsx:657 +#: src/view/screens/Settings/index.tsx:675 msgid "External Media Preferences" msgstr "외부 미디어 ì„¤ì •" -#: src/view/screens/Settings/index.tsx:648 +#: src/view/screens/Settings/index.tsx:666 msgid "External media settings" msgstr "외부 미디어 ì„¤ì •" @@ -1469,7 +1484,7 @@ msgstr "앱 비밀번호를 만들지 못했습니다." msgid "Failed to create the list. Check your internet connection and try again." msgstr "리스트를 만들지 못했습니다. ì¸í„°ë„· ì—°ê²°ì„ í™•ì¸í•œ 후 다시 시ë„하세요." -#: src/view/com/util/forms/PostDropdownBtn.tsx:110 +#: src/view/com/util/forms/PostDropdownBtn.tsx:125 msgid "Failed to delete post, please try again" msgstr "ê²Œì‹œë¬¼ì„ ì‚ì œí•˜ì§€ 못했습니다. 다시 시ë„í•´ 주세요" @@ -1478,11 +1493,11 @@ msgstr "ê²Œì‹œë¬¼ì„ ì‚ì œí•˜ì§€ 못했습니다. 다시 시ë„í•´ 주세요" msgid "Failed to load recommended feeds" msgstr "추천 피드를 불러오지 못했습니다" -#: src/Navigation.tsx:192 +#: src/Navigation.tsx:196 msgid "Feed" msgstr "피드" -#: src/view/com/feeds/FeedSourceCard.tsx:231 +#: src/view/com/feeds/FeedSourceCard.tsx:218 msgid "Feed by {0}" msgstr "{0} ë‹˜ì˜ í”¼ë“œ" @@ -1490,20 +1505,16 @@ msgstr "{0} ë‹˜ì˜ í”¼ë“œ" msgid "Feed offline" msgstr "피드 오프ë¼ì¸" -#: src/view/com/feeds/FeedPage.tsx:143 -#~ msgid "Feed Preferences" -#~ msgstr "피드 ì„¤ì •" - #: src/view/shell/desktop/RightNav.tsx:61 #: src/view/shell/Drawer.tsx:311 msgid "Feedback" msgstr "피드백" -#: src/Navigation.tsx:445 +#: src/Navigation.tsx:464 #: src/view/screens/Feeds.tsx:419 #: src/view/screens/Feeds.tsx:524 -#: src/view/screens/Profile.tsx:184 -#: src/view/shell/bottom-bar/BottomBar.tsx:181 +#: src/view/screens/Profile.tsx:192 +#: src/view/shell/bottom-bar/BottomBar.tsx:183 #: src/view/shell/desktop/LeftNav.tsx:342 #: src/view/shell/Drawer.tsx:476 #: src/view/shell/Drawer.tsx:477 @@ -1516,11 +1527,15 @@ msgstr "피드는 콘í…ì¸ ë¥¼ íë ˆì´ì…˜í•˜ê¸° 위해 사용ìžì— ì˜í•´ ë§Œ #: src/view/screens/SavedFeeds.tsx:156 msgid "Feeds are custom algorithms that users build with a little coding expertise. <0/> for more information." -msgstr "피드는 사용ìžê°€ ì•½ê°„ì˜ ì½”ë”© ì „ë¬¸ ì§€ì‹ìœ¼ë¡œ êµ¬ì¶•í• ìˆ˜ 있는 맞춤 ì•Œê³ ë¦¬ì¦˜ìž…ë‹ˆë‹¤. <0/>ì—서 ìžì„¸í•œ ë‚´ìš©ì„ í™•ì¸í•˜ì„¸ìš”." +msgstr "피드는 사용ìžê°€ ì•½ê°„ì˜ ì½”ë”© ì „ë¬¸ ì§€ì‹ë§Œìœ¼ë¡œ êµ¬ì¶•í• ìˆ˜ 있는 맞춤 ì•Œê³ ë¦¬ì¦˜ìž…ë‹ˆë‹¤. <0/>ì—서 ìžì„¸í•œ ë‚´ìš©ì„ í™•ì¸í•˜ì„¸ìš”." #: src/screens/Onboarding/StepTopicalFeeds.tsx:76 msgid "Feeds can be topical as well!" -msgstr "í”¼ë“œë„ í™”ì œê°€ ë 수 있습니다!" +msgstr "ì£¼ì œ 기반 í”¼ë“œë„ ìžˆìŠµë‹ˆë‹¤!" + +#: src/lib/moderation/useLabelBehaviorDescription.ts:66 +msgid "Filter from feeds" +msgstr "피드ì—서 í•„í„°ë§" #: src/screens/Onboarding/StepFinished.tsx:151 msgid "Finalizing" @@ -1540,21 +1555,17 @@ msgstr "Blueskyì—서 ì‚¬ìš©ìž ì°¾ê¸°" msgid "Find users with the search tool on the right" msgstr "ì˜¤ë¥¸ìª½ì˜ ê²€ìƒ‰ ë„구로 ì‚¬ìš©ìž ì°¾ê¸°" -#: src/view/com/auth/onboarding/RecommendedFollowsItem.tsx:150 +#: src/view/com/auth/onboarding/RecommendedFollowsItem.tsx:153 msgid "Finding similar accounts..." msgstr "ìœ ì‚¬í•œ ê³„ì •ì„ ì°¾ëŠ” 중…" #: src/view/screens/PreferencesFollowingFeed.tsx:111 msgid "Fine-tune the content you see on your Following feed." -msgstr "" - -#: src/view/screens/PreferencesHomeFeed.tsx:111 -#~ msgid "Fine-tune the content you see on your home screen." -#~ msgstr "홈 í™”ë©´ì— í‘œì‹œë˜ëŠ” 콘í…ì¸ ë¥¼ 미세 ì¡°ì •í•©ë‹ˆë‹¤." +msgstr "팔로우 중 í”¼ë“œì— í‘œì‹œë˜ëŠ” 콘í…ì¸ ë¥¼ 미세 ì¡°ì •í•©ë‹ˆë‹¤." #: src/view/screens/PreferencesThreads.tsx:60 msgid "Fine-tune the discussion threads." -msgstr "í† ë¡ ìŠ¤ë ˆë“œë¥¼ 미세 ì¡°ì •í•©ë‹ˆë‹¤." +msgstr "대화 ìŠ¤ë ˆë“œë¥¼ 미세 ì¡°ì •í•©ë‹ˆë‹¤." #: src/screens/Onboarding/index.tsx:38 msgid "Fitness" @@ -1574,22 +1585,27 @@ msgid "Flip vertically" msgstr "세로로 뒤집기" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:181 -#: src/view/com/post-thread/PostThreadFollowBtn.tsx:136 -#: src/view/com/profile/ProfileHeader.tsx:513 +#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:229 +#: src/view/com/post-thread/PostThreadFollowBtn.tsx:139 msgid "Follow" msgstr "팔로우" -#: src/view/com/profile/FollowButton.tsx:64 +#: src/view/com/profile/FollowButton.tsx:69 msgctxt "action" msgid "Follow" msgstr "팔로우" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:58 -#: src/view/com/post-thread/PostThreadFollowBtn.tsx:122 -#: src/view/com/profile/ProfileHeader.tsx:504 +#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:214 +#: src/view/com/post-thread/PostThreadFollowBtn.tsx:125 msgid "Follow {0}" msgstr "{0} ë‹˜ì„ íŒ”ë¡œìš°" +#: src/view/com/profile/ProfileMenu.tsx:242 +#: src/view/com/profile/ProfileMenu.tsx:253 +msgid "Follow Account" +msgstr "ê³„ì • 팔로우" + #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:179 msgid "Follow All" msgstr "ëª¨ë‘ íŒ”ë¡œìš°" @@ -1600,9 +1616,9 @@ msgstr "ì„ íƒí•œ ê³„ì •ì„ íŒ”ë¡œìš°í•˜ê³ ë‹¤ìŒ ë‹¨ê³„ë¥¼ ê³„ì† ì§„í–‰í•©ë‹ˆ #: src/view/com/auth/onboarding/RecommendedFollows.tsx:64 msgid "Follow some users to get started. We can recommend you more users based on who you find interesting." -msgstr "ì¼ë¶€ 사용ìžë¥¼ 팔로우하여 시작하세요. 관심 있는 사용ìžë¥¼ 기반으로 ë” ë§Žì€ ì‚¬ìš©ìžë¥¼ 추천해 드릴 수 있습니다." +msgstr "ì‹œìž‘í•˜ë ¤ë©´ ì‚¬ìš©ìž ëª‡ ëª…ì„ íŒ”ë¡œìš°í•´ 보세요. 누구ì—게 ê´€ì‹¬ì´ ìžˆëŠ”ì§€ë¥¼ 기반으로 ë” ë§Žì€ ì‚¬ìš©ìžë¥¼ 추천해 드릴 수 있습니다." -#: src/view/com/profile/ProfileCard.tsx:194 +#: src/view/com/profile/ProfileCard.tsx:214 msgid "Followed by {0}" msgstr "{0} ë‹˜ì´ íŒ”ë¡œìš°í•¨" @@ -1622,29 +1638,29 @@ msgstr "ë‹˜ì´ ë‚˜ë¥¼ 팔로우했습니다" msgid "Followers" msgstr "팔로워" -#: src/view/com/post-thread/PostThreadFollowBtn.tsx:136 -#: src/view/com/profile/ProfileHeader.tsx:495 +#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:227 +#: src/view/com/post-thread/PostThreadFollowBtn.tsx:139 #: src/view/screens/ProfileFollows.tsx:25 msgid "Following" msgstr "팔로우 중" -#: src/view/com/profile/ProfileHeader.tsx:149 +#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:89 msgid "Following {0}" -msgstr "{0} 팔로우 중" +msgstr "{0} ë‹˜ì„ íŒ”ë¡œìš°í–ˆìŠµë‹ˆë‹¤" -#: src/Navigation.tsx:248 -#: src/view/com/home/HomeHeaderLayout.web.tsx:45 -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:83 +#: src/Navigation.tsx:262 +#: src/view/com/home/HomeHeaderLayout.web.tsx:50 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:84 #: src/view/screens/PreferencesFollowingFeed.tsx:104 -#: src/view/screens/Settings/index.tsx:543 +#: src/view/screens/Settings/index.tsx:561 msgid "Following Feed Preferences" -msgstr "" +msgstr "팔로우 중 피드 ì„¤ì •" -#: src/view/com/profile/ProfileHeader.tsx:546 +#: src/screens/Profile/Header/Handle.tsx:24 msgid "Follows you" msgstr "나를 팔로우함" -#: src/view/com/profile/ProfileCard.tsx:141 +#: src/view/com/profile/ProfileCard.tsx:139 msgid "Follows You" msgstr "나를 팔로우함" @@ -1673,7 +1689,16 @@ msgstr "비밀번호 분실" msgid "Forgot Password" msgstr "비밀번호 분실" -#: src/view/com/posts/FeedItem.tsx:189 +#: src/lib/moderation/useReportOptions.ts:52 +msgid "Frequently Posts Unwanted Content" +msgstr "ìž¦ì€ ì›ì¹˜ 않는 콘í…ì¸ ê²Œì‹œ" + +#: src/screens/Hashtag.tsx:108 +#: src/screens/Hashtag.tsx:148 +msgid "From @{sanitizedAuthor}" +msgstr "@{sanitizedAuthor} ë‹˜ì˜ íƒœê·¸" + +#: src/view/com/posts/FeedItem.tsx:183 msgctxt "from-feed" msgid "From <0/>" msgstr "<0/>ì—서" @@ -1687,20 +1712,29 @@ msgstr "갤러리" msgid "Get Started" msgstr "시작하기" +#: src/lib/moderation/useReportOptions.ts:37 +msgid "Glaring violations of law or terms of service" +msgstr "명백한 ë²•ë¥ ë˜ëŠ” 서비스 약관 위반 행위" + +#: src/components/moderation/ScreenHider.tsx:143 +#: src/components/moderation/ScreenHider.tsx:152 #: src/view/com/auth/LoggedOut.tsx:81 #: src/view/com/auth/LoggedOut.tsx:82 -#: src/view/com/util/moderation/ScreenHider.tsx:123 #: src/view/shell/desktop/LeftNav.tsx:104 msgid "Go back" msgstr "뒤로" -#: src/view/screens/ProfileFeed.tsx:106 +#: src/screens/Profile/ErrorState.tsx:62 +#: src/screens/Profile/ErrorState.tsx:66 #: src/view/screens/ProfileFeed.tsx:111 -#: src/view/screens/ProfileList.tsx:897 -#: src/view/screens/ProfileList.tsx:902 +#: src/view/screens/ProfileFeed.tsx:116 +#: src/view/screens/ProfileList.tsx:916 +#: src/view/screens/ProfileList.tsx:921 msgid "Go Back" msgstr "뒤로" +#: src/components/ReportDialog/SelectReportOptionView.tsx:73 +#: src/components/ReportDialog/SubmitView.tsx:104 #: src/screens/Onboarding/Layout.tsx:104 #: src/screens/Onboarding/Layout.tsx:193 msgid "Go back to previous step" @@ -1719,13 +1753,25 @@ msgstr "@{queryMaybeHandle}(으)로 ì´ë™" msgid "Go to next" msgstr "다ìŒ" +#: src/lib/moderation/useGlobalLabelStrings.ts:46 +msgid "Graphic Media" +msgstr "그래픽 미디어" + #: src/view/com/modals/ChangeHandle.tsx:265 msgid "Handle" msgstr "핸들" -#: src/components/RichText.tsx:188 -msgid "Hashtag: {tag}" -msgstr "" +#: src/lib/moderation/useReportOptions.ts:32 +msgid "Harassment, trolling, or intolerance" +msgstr "ê´´ë¡íž˜, ë¶„ìŸ ìœ ë°œ ë˜ëŠ” 차별" + +#: src/Navigation.tsx:282 +msgid "Hashtag" +msgstr "해시태그" + +#: src/components/RichText.tsx:190 +msgid "Hashtag: #{tag}" +msgstr "해시태그: #{tag}" #: src/view/com/auth/create/CreateAccount.tsx:208 msgid "Having trouble?" @@ -1752,29 +1798,35 @@ msgstr "다ìŒì€ 사용ìžì˜ 관심사를 기반으로 한 몇 가지 ì£¼ì œë³ msgid "Here is your app password." msgstr "앱 비밀번호입니다." -#: src/screens/Onboarding/StepModeration/ModerationOption.tsx:41 -#: src/view/com/modals/ContentFilteringSettings.tsx:251 -#: src/view/com/util/moderation/ContentHider.tsx:105 -#: src/view/com/util/moderation/PostHider.tsx:108 +#: src/components/moderation/ContentHider.tsx:115 +#: src/components/moderation/GlobalModerationLabelPref.tsx:43 +#: src/components/moderation/PostHider.tsx:107 +#: src/lib/moderation/useLabelBehaviorDescription.ts:15 +#: src/lib/moderation/useLabelBehaviorDescription.ts:20 +#: src/lib/moderation/useLabelBehaviorDescription.ts:25 +#: src/lib/moderation/useLabelBehaviorDescription.ts:30 +#: src/screens/Onboarding/StepModeration/ModerationOption.tsx:52 +#: src/screens/Onboarding/StepModeration/ModerationOption.tsx:76 +#: src/view/com/util/forms/PostDropdownBtn.tsx:328 msgid "Hide" msgstr "숨기기" -#: src/view/com/modals/ContentFilteringSettings.tsx:224 #: src/view/com/notifications/FeedItem.tsx:325 msgctxt "action" msgid "Hide" msgstr "숨기기" -#: src/view/com/util/forms/PostDropdownBtn.tsx:232 +#: src/view/com/util/forms/PostDropdownBtn.tsx:276 +#: src/view/com/util/forms/PostDropdownBtn.tsx:278 msgid "Hide post" msgstr "게시물 숨기기" -#: src/view/com/util/moderation/ContentHider.tsx:67 -#: src/view/com/util/moderation/PostHider.tsx:61 +#: src/components/moderation/ContentHider.tsx:67 +#: src/components/moderation/PostHider.tsx:64 msgid "Hide the content" msgstr "콘í…ì¸ ìˆ¨ê¸°ê¸°" -#: src/view/com/util/forms/PostDropdownBtn.tsx:236 +#: src/view/com/util/forms/PostDropdownBtn.tsx:325 msgid "Hide this post?" msgstr "ì´ ê²Œì‹œë¬¼ì„ ìˆ¨ê¸°ì‹œê² ìŠµë‹ˆê¹Œ?" @@ -1782,10 +1834,6 @@ msgstr "ì´ ê²Œì‹œë¬¼ì„ ìˆ¨ê¸°ì‹œê² ìŠµë‹ˆê¹Œ?" msgid "Hide user list" msgstr "ì‚¬ìš©ìž ë¦¬ìŠ¤íŠ¸ 숨기기" -#: src/view/com/profile/ProfileHeader.tsx:487 -msgid "Hides posts from {0} in your feed" -msgstr "피드ì—서 {0} ë‹˜ì˜ ê²Œì‹œë¬¼ì„ ìˆ¨ê¹ë‹ˆë‹¤" - #: src/view/com/posts/FeedErrorMessage.tsx:111 msgid "Hmm, some kind of issue occurred when contacting the feed server. Please let the feed owner know about this issue." msgstr "피드 ì„œë²„ì— ì—°ê²°í•˜ëŠ” 중 ì–´ë–¤ ë¬¸ì œê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤. 피드 ì†Œìœ ìžì—게 ì´ ë¬¸ì œì— ëŒ€í•´ ì•Œë ¤ì£¼ì„¸ìš”." @@ -1806,22 +1854,23 @@ msgstr "피드 서버ì—서 ìž˜ëª»ëœ ì‘ë‹µì„ ë³´ëƒˆìŠµë‹ˆë‹¤. 피드 ì†Œìœ ìž msgid "Hmm, we're having trouble finding this feed. It may have been deleted." msgstr "ì´ í”¼ë“œë¥¼ 찾는 ë° ë¬¸ì œê°€ 있습니다. 피드가 ì‚ì œë˜ì—ˆì„ 수 있습니다." -#: src/Navigation.tsx:435 -#: src/view/shell/bottom-bar/BottomBar.tsx:137 +#: src/screens/Moderation/index.tsx:61 +msgid "Hmmmm, it seems we're having trouble loading this data. See below for more details. If this issue persists, please contact us." +msgstr "ì´ ë°ì´í„°ë¥¼ 불러오는 ë° ë¬¸ì œê°€ 있는 것 같습니다. ìžì„¸í•œ ë‚´ìš©ì€ ì•„ëž˜ë¥¼ 참조하세요. ì´ ë¬¸ì œê°€ ì§€ì†ë˜ë©´ 문ì˜í•´ 주세요." + +#: src/screens/Profile/ErrorState.tsx:31 +msgid "Hmmmm, we couldn't load that moderation service." +msgstr "ê²€í† ì„œë¹„ìŠ¤ë¥¼ 불러올 수 없습니다." + +#: src/Navigation.tsx:454 +#: src/view/shell/bottom-bar/BottomBar.tsx:139 #: src/view/shell/desktop/LeftNav.tsx:306 #: src/view/shell/Drawer.tsx:398 #: src/view/shell/Drawer.tsx:399 msgid "Home" msgstr "홈" -#: src/Navigation.tsx:247 -#: src/view/com/pager/FeedsTabBarMobile.tsx:123 -#: src/view/screens/PreferencesHomeFeed.tsx:104 -#: src/view/screens/Settings/index.tsx:543 -#~ msgid "Home Feed Preferences" -#~ msgstr "홈 피드 ì„¤ì •" - -#: src/view/com/auth/create/Step1.tsx:82 +#: src/view/com/auth/create/Step1.tsx:75 #: src/view/com/auth/login/ForgotPasswordForm.tsx:120 msgid "Hosting provider" msgstr "호스팅 ì œê³µìž" @@ -1850,9 +1899,21 @@ msgstr "대체 í…스트가 긴 경우 대체 í…스트 확장 ìƒíƒœë¥¼ ì „í™˜í msgid "If none are selected, suitable for all ages." msgstr "ì•„ë¬´ê²ƒë„ ì„ íƒí•˜ì§€ 않으면 ëª¨ë“ ì—°ë ¹ëŒ€ì— ì 합하다는 뜻입니다." +#: src/view/screens/ProfileList.tsx:610 +msgid "If you delete this list, you won't be able to recover it." +msgstr "ì´ ë¦¬ìŠ¤íŠ¸ë¥¼ ì‚ì œí•˜ë©´ 다시 ë³µêµ¬í• ìˆ˜ 없습니다." + +#: src/view/com/util/forms/PostDropdownBtn.tsx:316 +msgid "If you remove this post, you won't be able to recover it." +msgstr "ì´ ê²Œì‹œë¬¼ì„ ì‚ì œí•˜ë©´ 다시 ë³µêµ¬í• ìˆ˜ 없습니다." + #: src/view/com/modals/ChangePassword.tsx:146 msgid "If you want to change your password, we will send you a code to verify that this is your account." -msgstr "" +msgstr "비밀번호를 ë³€ê²½í•˜ê³ ì‹¶ë‹¤ë©´ ë³¸ì¸ ê³„ì •ìž„ì„ í™•ì¸í• 수 있는 코드를 ë³´ë‚´ë“œë¦¬ê² ìŠµë‹ˆë‹¤." + +#: src/lib/moderation/useReportOptions.ts:36 +msgid "Illegal and Urgent" +msgstr "불법 ë° ê¸´ê¸‰ 사í•" #: src/view/com/util/images/Gallery.tsx:38 msgid "Image" @@ -1862,10 +1923,9 @@ msgstr "ì´ë¯¸ì§€" msgid "Image alt text" msgstr "ì´ë¯¸ì§€ 대체 í…스트" -#: src/view/com/util/UserAvatar.tsx:311 -#: src/view/com/util/UserBanner.tsx:118 -msgid "Image options" -msgstr "ì´ë¯¸ì§€ 옵션" +#: src/lib/moderation/useReportOptions.ts:47 +msgid "Impersonation or false claims about identity or affiliation" +msgstr "ì‹ ì› ë˜ëŠ” 소ì†ì— 대한 ì‚¬ì¹ ë˜ëŠ” 허위 주장" #: src/view/com/auth/login/SetNewPasswordForm.tsx:138 msgid "Input code sent to your email for password reset" @@ -1875,11 +1935,11 @@ msgstr "비밀번호 ìž¬ì„¤ì •ì„ ìœ„í•´ ì´ë©”ì¼ë¡œ ì „ì†¡ëœ ì½”ë“œë¥¼ ìž…ë ¥ msgid "Input confirmation code for account deletion" msgstr "ê³„ì • ì‚ì œë¥¼ 위한 í™•ì¸ ì½”ë“œë¥¼ ìž…ë ¥í•©ë‹ˆë‹¤" -#: src/view/com/auth/create/Step1.tsx:200 +#: src/view/com/auth/create/Step1.tsx:177 msgid "Input email for Bluesky account" msgstr "Bluesky ê³„ì •ì— ì‚¬ìš©í• ì´ë©”ì¼ì„ ìž…ë ¥í•©ë‹ˆë‹¤" -#: src/view/com/auth/create/Step1.tsx:158 +#: src/view/com/auth/create/Step1.tsx:151 msgid "Input invite code to proceed" msgstr "진행하기 위해 초대 코드를 ìž…ë ¥í•©ë‹ˆë‹¤" @@ -1895,10 +1955,6 @@ msgstr "새 비밀번호를 ìž…ë ¥í•©ë‹ˆë‹¤" msgid "Input password for account deletion" msgstr "ê³„ì •ì„ ì‚ì œí•˜ê¸° 위해 비밀번호를 ìž…ë ¥í•©ë‹ˆë‹¤" -#: src/view/com/auth/create/Step2.tsx:196 -#~ msgid "Input phone number for SMS verification" -#~ msgstr "SMS ì¸ì¦ì— ì‚¬ìš©í• ì „í™”ë²ˆí˜¸ë¥¼ ìž…ë ¥í•©ë‹ˆë‹¤" - #: src/view/com/auth/login/LoginForm.tsx:230 msgid "Input the password tied to {identifier}" msgstr "{identifier}ì— ì—°ê²°ëœ ë¹„ë°€ë²ˆí˜¸ë¥¼ ìž…ë ¥í•©ë‹ˆë‹¤" @@ -1907,14 +1963,6 @@ msgstr "{identifier}ì— ì—°ê²°ëœ ë¹„ë°€ë²ˆí˜¸ë¥¼ ìž…ë ¥í•©ë‹ˆë‹¤" msgid "Input the username or email address you used at signup" msgstr "가입 시 사용한 ì‚¬ìš©ìž ì´ë¦„ ë˜ëŠ” ì´ë©”ì¼ ì£¼ì†Œë¥¼ ìž…ë ¥í•©ë‹ˆë‹¤" -#: src/view/com/auth/create/Step2.tsx:271 -#~ msgid "Input the verification code we have texted to you" -#~ msgstr "ë¬¸ìž ë©”ì‹œì§€ë¡œ ì „ì†¡ëœ ì¸ì¦ 코드를 ìž…ë ¥í•©ë‹ˆë‹¤" - -#: src/view/com/modals/Waitlist.tsx:90 -msgid "Input your email to get on the Bluesky waitlist" -msgstr "Bluesky ëŒ€ê¸°ìž ëª…ë‹¨ì— ë“±ë¡í•˜ë ¤ë©´ ì´ë©”ì¼ì„ ìž…ë ¥í•©ë‹ˆë‹¤" - #: src/view/com/auth/login/LoginForm.tsx:229 msgid "Input your password" msgstr "비밀번호를 ìž…ë ¥í•©ë‹ˆë‹¤" @@ -1923,7 +1971,7 @@ msgstr "비밀번호를 ìž…ë ¥í•©ë‹ˆë‹¤" msgid "Input your user handle" msgstr "ì‚¬ìš©ìž í•¸ë“¤ì„ ìž…ë ¥í•©ë‹ˆë‹¤" -#: src/view/com/post-thread/PostThreadItem.tsx:226 +#: src/view/com/post-thread/PostThreadItem.tsx:225 msgid "Invalid or unsupported post record" msgstr "ìœ íš¨í•˜ì§€ 않거나 ì§€ì›ë˜ì§€ 않는 게시물 기ë¡" @@ -1931,16 +1979,12 @@ msgstr "ìœ íš¨í•˜ì§€ 않거나 ì§€ì›ë˜ì§€ 않는 게시물 기ë¡" msgid "Invalid username or password" msgstr "ìž˜ëª»ëœ ì‚¬ìš©ìž ì´ë¦„ ë˜ëŠ” 비밀번호" -#: src/view/screens/Settings.tsx:411 -#~ msgid "Invite" -#~ msgstr "초대" - #: src/view/com/modals/InviteCodes.tsx:93 msgid "Invite a Friend" msgstr "친구 초대하기" -#: src/view/com/auth/create/Step1.tsx:148 -#: src/view/com/auth/create/Step1.tsx:157 +#: src/view/com/auth/create/Step1.tsx:141 +#: src/view/com/auth/create/Step1.tsx:150 msgid "Invite code" msgstr "초대 코드" @@ -1952,10 +1996,6 @@ msgstr "초대 코드가 올바르지 않습니다. 코드를 올바르게 ìž…ë msgid "Invite codes: {0} available" msgstr "초대 코드: {0}ê°œ 사용 가능" -#: src/view/shell/Drawer.tsx:645 -#~ msgid "Invite codes: {invitesAvailable} available" -#~ msgstr "초대 코드: {invitesAvailable}ê°œ 사용 가능" - #: src/view/com/modals/InviteCodes.tsx:169 msgid "Invite codes: 1 available" msgstr "초대 코드: 1ê°œ 사용 가능" @@ -1969,37 +2009,56 @@ msgstr "ë‚´ê°€ 팔로우하는 ì‚¬ëžŒë“¤ì˜ ê²Œì‹œë¬¼ì´ ì˜¬ë¼ì˜¤ëŠ” 대로 표 msgid "Jobs" msgstr "채용" -#: src/view/com/modals/Waitlist.tsx:67 -msgid "Join the waitlist" -msgstr "ëŒ€ê¸°ìž ëª…ë‹¨ 등ë¡" - -#: src/view/com/auth/create/Step1.tsx:174 -#: src/view/com/auth/create/Step1.tsx:178 -msgid "Join the waitlist." -msgstr "ëŒ€ê¸°ìž ëª…ë‹¨ì— ë“±ë¡í•˜ì„¸ìš”." - -#: src/view/com/modals/Waitlist.tsx:128 -msgid "Join Waitlist" -msgstr "ëŒ€ê¸°ìž ëª…ë‹¨ 등ë¡" - #: src/screens/Onboarding/index.tsx:24 msgid "Journalism" msgstr "ì €ë„리즘" +#: src/components/moderation/LabelsOnMe.tsx:59 +msgid "label has been placed on this {labelTarget}" +msgstr "ì´ {labelTarget}ì— ë¼ë²¨ì´ ì§€ì •ë˜ì—ˆìŠµë‹ˆë‹¤" + +#: src/components/moderation/ContentHider.tsx:144 +msgid "Labeled by {0}." +msgstr "{0} ë‹˜ì´ ë¼ë²¨ ì§€ì •í•¨." + +#: src/components/moderation/ContentHider.tsx:142 +msgid "Labeled by the author." +msgstr "작성ìžê°€ ë¼ë²¨ ì§€ì •í•¨." + +#: src/view/screens/Profile.tsx:186 +msgid "Labels" +msgstr "ë¼ë²¨" + +#: src/screens/Profile/Sections/Labels.tsx:161 +msgid "Labels are annotations on users and content. They can be used to hide, warn, and categorize the network." +msgstr "ë¼ë²¨ì€ ì‚¬ìš©ìž ë° ì½˜í…ì¸ ì— ëŒ€í•œ 주ì„입니다. 네트워í¬ë¥¼ ìˆ¨ê¸°ê³ , ê²½ê³ í•˜ê³ , 분류하는 ë° ì‚¬ìš©í• ìˆ˜ 있습니다." + +#: src/components/moderation/LabelsOnMe.tsx:61 +msgid "labels have been placed on this {labelTarget}" +msgstr "ë¼ë²¨ì´ {labelTarget}ì— ì§€ì •ë˜ì—ˆìŠµë‹ˆë‹¤" + +#: src/components/moderation/LabelsOnMeDialog.tsx:63 +msgid "Labels on your account" +msgstr "ë‚´ ê³„ì •ì˜ ë¼ë²¨" + +#: src/components/moderation/LabelsOnMeDialog.tsx:65 +msgid "Labels on your content" +msgstr "ë‚´ 콘í…ì¸ ì˜ ë¼ë²¨" + #: src/view/com/composer/select-language/SelectLangBtn.tsx:104 msgid "Language selection" msgstr "언어 ì„ íƒ" -#: src/view/screens/Settings/index.tsx:594 +#: src/view/screens/Settings/index.tsx:612 msgid "Language settings" msgstr "언어 ì„¤ì •" -#: src/Navigation.tsx:140 +#: src/Navigation.tsx:144 #: src/view/screens/LanguageSettings.tsx:89 msgid "Language Settings" msgstr "언어 ì„¤ì •" -#: src/view/screens/Settings/index.tsx:603 +#: src/view/screens/Settings/index.tsx:621 msgid "Languages" msgstr "언어" @@ -2007,28 +2066,28 @@ msgstr "언어" msgid "Last step!" msgstr "마지막 단계예요!" -#: src/view/com/util/moderation/ContentHider.tsx:103 -msgid "Learn more" -msgstr "ë” ì•Œì•„ë³´ê¸°" - -#: src/view/com/util/moderation/PostAlerts.tsx:47 -#: src/view/com/util/moderation/ProfileHeaderAlerts.tsx:65 -#: src/view/com/util/moderation/ScreenHider.tsx:104 +#: src/components/moderation/ScreenHider.tsx:128 msgid "Learn More" msgstr "ë” ì•Œì•„ë³´ê¸°" -#: src/view/com/util/moderation/ContentHider.tsx:85 -#: src/view/com/util/moderation/PostAlerts.tsx:40 -#: src/view/com/util/moderation/PostHider.tsx:78 -#: src/view/com/util/moderation/ProfileHeaderAlerts.tsx:49 -#: src/view/com/util/moderation/ScreenHider.tsx:101 +#: src/components/moderation/ContentHider.tsx:65 +#: src/components/moderation/ContentHider.tsx:128 +msgid "Learn more about the moderation applied to this content." +msgstr "ì´ ì½˜í…ì¸ ì— ì ìš©ëœ ê²€í† ì„¤ì •ì— ëŒ€í•´ ìžì„¸ížˆ 알아보세요." + +#: src/components/moderation/PostHider.tsx:85 +#: src/components/moderation/ScreenHider.tsx:125 msgid "Learn more about this warning" msgstr "ì´ ê²½ê³ ì— ëŒ€í•´ ë” ì•Œì•„ë³´ê¸°" -#: src/view/screens/Moderation.tsx:262 +#: src/screens/Moderation/index.tsx:555 msgid "Learn more about what is public on Bluesky." msgstr "Blueskyì—서 공개ë˜ëŠ” í•ëª©ì— ëŒ€í•´ ìžì„¸ížˆ 알아보세요." +#: src/components/moderation/ContentHider.tsx:152 +msgid "Learn more." +msgstr "ë” ì•Œì•„ë³´ê¸°" + #: src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx:82 msgid "Leave them all unchecked to see any language." msgstr "ëª¨ë“ ì–¸ì–´ë¥¼ ë³´ë ¤ë©´ ëª¨ë‘ ì„ íƒí•˜ì§€ ì•Šì€ ìƒíƒœë¡œ ë‘세요." @@ -2041,7 +2100,7 @@ msgstr "Bluesky ë– ë‚˜ê¸°" msgid "left to go." msgstr "명 남았습니다." -#: src/view/screens/Settings/index.tsx:278 +#: src/view/screens/Settings/index.tsx:292 msgid "Legacy storage cleared, you need to restart the app now." msgstr "ë ˆê±°ì‹œ ìŠ¤í† ë¦¬ì§€ê°€ 지워졌으며 지금 ì•±ì„ ë‹¤ì‹œ 시작해야 합니다." @@ -2054,38 +2113,42 @@ msgstr "비밀번호를 ìž¬ì„¤ì •í•´ 봅시다!" msgid "Let's go!" msgstr "출발!" -#: src/view/com/util/UserAvatar.tsx:248 -#: src/view/com/util/UserBanner.tsx:62 -msgid "Library" -msgstr "ë¼ì´ë¸ŒëŸ¬ë¦¬" - -#: src/view/screens/Settings/index.tsx:479 +#: src/view/screens/Settings/index.tsx:497 msgid "Light" msgstr "ë°ìŒ" -#: src/view/com/util/post-ctrls/PostCtrls.tsx:182 -#: src/view/com/util/post-ctrls/PostCtrls.tsx:216 +#: src/view/com/util/post-ctrls/PostCtrls.tsx:185 msgid "Like" msgstr "좋아요" -#: src/view/screens/ProfileFeed.tsx:591 +#: src/screens/Profile/Header/ProfileHeaderLabeler.tsx:257 +#: src/view/screens/ProfileFeed.tsx:572 msgid "Like this feed" msgstr "ì´ í”¼ë“œì— ì¢‹ì•„ìš” 표시" -#: src/Navigation.tsx:197 +#: src/components/LikesDialog.tsx:87 +#: src/Navigation.tsx:201 +#: src/Navigation.tsx:206 msgid "Liked by" msgstr "좋아요 표시한 사용ìž" +#: src/screens/Profile/ProfileLabelerLikedBy.tsx:42 #: src/view/screens/PostLikedBy.tsx:27 #: src/view/screens/ProfileFeedLikedBy.tsx:27 msgid "Liked By" msgstr "좋아요 표시한 사용ìž" -#: src/view/com/feeds/FeedSourceCard.tsx:279 +#: src/view/com/feeds/FeedSourceCard.tsx:268 msgid "Liked by {0} {1}" msgstr "{0}ëª…ì˜ ì‚¬ìš©ìžê°€ 좋아함" -#: src/view/screens/ProfileFeed.tsx:606 +#: src/components/LabelingServiceCard/index.tsx:72 +msgid "Liked by {count} {0}" +msgstr "{count}ëª…ì˜ ì‚¬ìš©ìžê°€ 좋아함" + +#: src/screens/Profile/Header/ProfileHeaderLabeler.tsx:277 +#: src/screens/Profile/Header/ProfileHeaderLabeler.tsx:291 +#: src/view/screens/ProfileFeed.tsx:587 msgid "Liked by {likeCount} {0}" msgstr "{likeCount}ëª…ì˜ ì‚¬ìš©ìžê°€ 좋아함" @@ -2097,15 +2160,15 @@ msgstr "ë‹˜ì´ ë‚´ 맞춤 피드를 좋아합니다" msgid "liked your post" msgstr "ë‹˜ì´ ë‚´ ê²Œì‹œë¬¼ì„ ì¢‹ì•„í•©ë‹ˆë‹¤" -#: src/view/screens/Profile.tsx:183 +#: src/view/screens/Profile.tsx:191 msgid "Likes" msgstr "좋아요" -#: src/view/com/post-thread/PostThreadItem.tsx:183 +#: src/view/com/post-thread/PostThreadItem.tsx:182 msgid "Likes on this post" msgstr "ì´ ê²Œì‹œë¬¼ì„ ì¢‹ì•„ìš” 표시합니다" -#: src/Navigation.tsx:166 +#: src/Navigation.tsx:170 msgid "List" msgstr "리스트" @@ -2113,15 +2176,15 @@ msgstr "리스트" msgid "List Avatar" msgstr "리스트 아바타" -#: src/view/screens/ProfileList.tsx:324 +#: src/view/screens/ProfileList.tsx:311 msgid "List blocked" msgstr "리스트 차단ë¨" -#: src/view/com/feeds/FeedSourceCard.tsx:233 +#: src/view/com/feeds/FeedSourceCard.tsx:220 msgid "List by {0}" msgstr "{0} ë‹˜ì˜ ë¦¬ìŠ¤íŠ¸" -#: src/view/screens/ProfileList.tsx:378 +#: src/view/screens/ProfileList.tsx:355 msgid "List deleted" msgstr "리스트 ì‚ì œë¨" @@ -2133,24 +2196,25 @@ msgstr "리스트 뮤트ë¨" msgid "List Name" msgstr "리스트 ì´ë¦„" -#: src/view/screens/ProfileList.tsx:343 +#: src/view/screens/ProfileList.tsx:325 msgid "List unblocked" msgstr "리스트 차단 í•´ì œë¨" -#: src/view/screens/ProfileList.tsx:302 +#: src/view/screens/ProfileList.tsx:297 msgid "List unmuted" msgstr "리스트 언뮤트ë¨" -#: src/Navigation.tsx:110 -#: src/view/screens/Profile.tsx:185 +#: src/Navigation.tsx:114 +#: src/view/screens/Profile.tsx:187 +#: src/view/screens/Profile.tsx:193 #: src/view/shell/desktop/LeftNav.tsx:379 #: src/view/shell/Drawer.tsx:492 #: src/view/shell/Drawer.tsx:493 msgid "Lists" msgstr "리스트" -#: src/view/com/post-thread/PostThread.tsx:333 -#: src/view/com/post-thread/PostThread.tsx:341 +#: src/view/com/post-thread/PostThread.tsx:334 +#: src/view/com/post-thread/PostThread.tsx:342 msgid "Load more posts" msgstr "ë” ë§Žì€ ê²Œì‹œë¬¼ 불러오기" @@ -2158,10 +2222,10 @@ msgstr "ë” ë§Žì€ ê²Œì‹œë¬¼ 불러오기" msgid "Load new notifications" msgstr "새 알림 불러오기" +#: src/screens/Profile/Sections/Feed.tsx:70 #: src/view/com/feeds/FeedPage.tsx:115 -#: src/view/screens/Profile.tsx:440 #: src/view/screens/ProfileFeed.tsx:495 -#: src/view/screens/ProfileList.tsx:681 +#: src/view/screens/ProfileList.tsx:695 msgid "Load new posts" msgstr "새 게시물 불러오기" @@ -2169,11 +2233,7 @@ msgstr "새 게시물 불러오기" msgid "Loading..." msgstr "불러오는 중…" -#: src/view/com/modals/ServerInput.tsx:50 -#~ msgid "Local dev server" -#~ msgstr "로컬 개발 서버" - -#: src/Navigation.tsx:207 +#: src/Navigation.tsx:221 msgid "Log" msgstr "로그" @@ -2184,7 +2244,7 @@ msgstr "로그" msgid "Log out" msgstr "로그아웃" -#: src/view/screens/Moderation.tsx:155 +#: src/screens/Moderation/index.tsx:448 msgid "Logged-out visibility" msgstr "로그아웃 표시" @@ -2196,19 +2256,19 @@ msgstr "목ë¡ì— 없는 ê³„ì •ìœ¼ë¡œ 로그ì¸" msgid "Make sure this is where you intend to go!" msgstr "ì´ê³³ì´ ë‹¹ì‹ ì´ ê°€ê³ ìž í•˜ëŠ” ê³³ì¸ì§€ 확ì¸í•˜ì„¸ìš”!" -#: src/components/dialogs/MutedWords.tsx:71 +#: src/components/dialogs/MutedWords.tsx:83 msgid "Manage your muted words and tags" -msgstr "" +msgstr "뮤트한 단어 ë° íƒœê·¸ 관리" #: src/view/com/auth/create/Step2.tsx:118 msgid "May not be longer than 253 characters" -msgstr "" +msgstr "253ìžë¥¼ ë„˜ì„ ìˆ˜ 없습니다" #: src/view/com/auth/create/Step2.tsx:109 msgid "May only contain letters and numbers" -msgstr "" +msgstr "문ìžì™€ 숫ìžë§Œ ìž…ë ¥í• ìˆ˜ 있습니다" -#: src/view/screens/Profile.tsx:182 +#: src/view/screens/Profile.tsx:190 msgid "Media" msgstr "미디어" @@ -2220,36 +2280,44 @@ msgstr "멘션한 사용ìž" msgid "Mentioned users" msgstr "멘션한 사용ìž" -#: src/view/com/util/ViewHeader.tsx:81 +#: src/view/com/util/ViewHeader.tsx:87 #: src/view/screens/Search/Search.tsx:646 msgid "Menu" msgstr "메뉴" -#: src/view/com/posts/FeedErrorMessage.tsx:197 +#: src/view/com/posts/FeedErrorMessage.tsx:192 msgid "Message from server: {0}" msgstr "서버ì—서 보낸 메시지: {0}" -#: src/Navigation.tsx:115 -#: src/view/screens/Moderation.tsx:66 -#: src/view/screens/Settings/index.tsx:625 +#: src/lib/moderation/useReportOptions.ts:45 +msgid "Misleading Account" +msgstr "ì˜¤í•´ì˜ ì†Œì§€ê°€ 있는 ê³„ì •" + +#: src/Navigation.tsx:119 +#: src/screens/Moderation/index.tsx:106 +#: src/view/screens/Settings/index.tsx:643 #: src/view/shell/desktop/LeftNav.tsx:397 #: src/view/shell/Drawer.tsx:511 #: src/view/shell/Drawer.tsx:512 msgid "Moderation" msgstr "ê²€í† " +#: src/components/moderation/ModerationDetailsDialog.tsx:113 +msgid "Moderation details" +msgstr "ê²€í† ì„¸ë¶€ ì •ë³´" + #: src/view/com/lists/ListCard.tsx:93 #: src/view/com/modals/UserAddRemoveLists.tsx:206 msgid "Moderation list by {0}" msgstr "{0} ë‹˜ì˜ ê²€í† ë¦¬ìŠ¤íŠ¸" -#: src/view/screens/ProfileList.tsx:774 +#: src/view/screens/ProfileList.tsx:789 msgid "Moderation list by <0/>" msgstr "<0/> ë‹˜ì˜ ê²€í† ë¦¬ìŠ¤íŠ¸" #: src/view/com/lists/ListCard.tsx:91 #: src/view/com/modals/UserAddRemoveLists.tsx:204 -#: src/view/screens/ProfileList.tsx:772 +#: src/view/screens/ProfileList.tsx:787 msgid "Moderation list by you" msgstr "ë‚´ ê²€í† ë¦¬ìŠ¤íŠ¸" @@ -2261,110 +2329,113 @@ msgstr "ê²€í† ë¦¬ìŠ¤íŠ¸ ìƒì„±ë¨" msgid "Moderation list updated" msgstr "ê²€í† ë¦¬ìŠ¤íŠ¸ ì—…ë°ì´íЏë¨" -#: src/view/screens/Moderation.tsx:114 +#: src/screens/Moderation/index.tsx:246 msgid "Moderation lists" msgstr "ê²€í† ë¦¬ìŠ¤íŠ¸" -#: src/Navigation.tsx:120 +#: src/Navigation.tsx:124 #: src/view/screens/ModerationModlists.tsx:58 msgid "Moderation Lists" msgstr "ê²€í† ë¦¬ìŠ¤íŠ¸" -#: src/view/screens/Settings/index.tsx:619 +#: src/view/screens/Settings/index.tsx:637 msgid "Moderation settings" msgstr "ê²€í† ì„¤ì •" -#: src/view/com/modals/ModerationDetails.tsx:35 +#: src/Navigation.tsx:216 +msgid "Moderation states" +msgstr "ê²€í† ìƒíƒœ" + +#: src/screens/Moderation/index.tsx:218 +msgid "Moderation tools" +msgstr "ê²€í† ë„구" + +#: src/components/moderation/ModerationDetailsDialog.tsx:49 +#: src/lib/moderation/useModerationCauseDescription.ts:40 msgid "Moderator has chosen to set a general warning on the content." -msgstr "중재ìžê°€ 콘í…ì¸ ì— ì¼ë°˜ ê²½ê³ ë¥¼ ì„¤ì •í–ˆìŠµë‹ˆë‹¤." +msgstr "관리ìžê°€ 콘í…ì¸ ì— ì¼ë°˜ ê²½ê³ ë¥¼ ì„¤ì •í–ˆìŠµë‹ˆë‹¤." -#: src/view/shell/desktop/Feeds.tsx:63 +#: src/view/shell/desktop/Feeds.tsx:65 msgid "More feeds" msgstr "피드 ë” ë³´ê¸°" -#: src/view/com/profile/ProfileHeader.tsx:523 -#: src/view/screens/ProfileFeed.tsx:363 -#: src/view/screens/ProfileList.tsx:617 +#: src/view/screens/ProfileList.tsx:599 msgid "More options" msgstr "옵션 ë” ë³´ê¸°" -#: src/view/com/util/forms/PostDropdownBtn.tsx:315 -msgid "More post options" -msgstr "게시물 옵션 ë” ë³´ê¸°" - #: src/view/screens/PreferencesThreads.tsx:82 msgid "Most-liked replies first" msgstr "좋아요 ë§Žì€ ìˆœ" #: src/view/com/auth/create/Step2.tsx:122 msgid "Must be at least 3 characters" -msgstr "" +msgstr "최소 3ìž ì´ìƒì´ì–´ì•¼ 합니다" -#: src/components/TagMenu/index.tsx:253 +#: src/components/TagMenu/index.tsx:249 msgid "Mute" -msgstr "" +msgstr "뮤트" -#: src/components/TagMenu/index.web.tsx:91 +#: src/components/TagMenu/index.web.tsx:105 msgid "Mute {truncatedTag}" -msgstr "" +msgstr "{truncatedTag} 뮤트" -#: src/view/com/profile/ProfileHeader.tsx:327 +#: src/view/com/profile/ProfileMenu.tsx:279 +#: src/view/com/profile/ProfileMenu.tsx:286 msgid "Mute Account" msgstr "ê³„ì • 뮤트" -#: src/view/screens/ProfileList.tsx:544 +#: src/view/screens/ProfileList.tsx:518 msgid "Mute accounts" msgstr "ê³„ì • 뮤트" -#: src/components/TagMenu/index.tsx:211 -msgid "Mute all {tag} posts" -msgstr "" +#: src/components/TagMenu/index.tsx:209 +msgid "Mute all {displayTag} posts" +msgstr "ëª¨ë“ {displayTag} 게시물 뮤트" -#: src/components/dialogs/MutedWords.tsx:131 +#: src/components/dialogs/MutedWords.tsx:149 msgid "Mute in tags only" -msgstr "" +msgstr "태그ì—서만 뮤트" -#: src/components/dialogs/MutedWords.tsx:116 +#: src/components/dialogs/MutedWords.tsx:134 msgid "Mute in text & tags" -msgstr "" +msgstr "글 ë° íƒœê·¸ì—서 뮤트" -#: src/view/screens/ProfileList.tsx:491 +#: src/view/screens/ProfileList.tsx:461 +#: src/view/screens/ProfileList.tsx:624 msgid "Mute list" msgstr "리스트 뮤트" -#: src/view/screens/ProfileList.tsx:275 +#: src/view/screens/ProfileList.tsx:619 msgid "Mute these accounts?" msgstr "ì´ ê³„ì •ë“¤ì„ ë®¤íŠ¸í•˜ì‹œê² ìŠµë‹ˆê¹Œ?" -#: src/view/screens/ProfileList.tsx:279 -msgid "Mute this List" -msgstr "ì´ ë¦¬ìŠ¤íŠ¸ 뮤트" - -#: src/components/dialogs/MutedWords.tsx:109 +#: src/components/dialogs/MutedWords.tsx:127 msgid "Mute this word in post text and tags" -msgstr "" +msgstr "게시물 글 ë° íƒœê·¸ì—서 ì´ ë‹¨ì–´ 뮤트하기" -#: src/components/dialogs/MutedWords.tsx:124 +#: src/components/dialogs/MutedWords.tsx:142 msgid "Mute this word in tags only" -msgstr "" +msgstr "태그ì—서만 ì´ ë‹¨ì–´ 뮤트하기" -#: src/view/com/util/forms/PostDropdownBtn.tsx:202 +#: src/view/com/util/forms/PostDropdownBtn.tsx:251 +#: src/view/com/util/forms/PostDropdownBtn.tsx:257 msgid "Mute thread" msgstr "ìŠ¤ë ˆë“œ 뮤트" -#: src/view/com/util/forms/PostDropdownBtn.tsx:216 +#: src/view/com/util/forms/PostDropdownBtn.tsx:267 +#: src/view/com/util/forms/PostDropdownBtn.tsx:269 msgid "Mute words & tags" -msgstr "" +msgstr "단어 ë° íƒœê·¸ 뮤트" #: src/view/com/lists/ListCard.tsx:102 msgid "Muted" msgstr "뮤트ë¨" -#: src/view/screens/Moderation.tsx:128 +#: src/screens/Moderation/index.tsx:258 msgid "Muted accounts" msgstr "뮤트한 ê³„ì •" -#: src/Navigation.tsx:125 +#: src/Navigation.tsx:129 #: src/view/screens/ModerationMutedAccounts.tsx:107 msgid "Muted Accounts" msgstr "뮤트한 ê³„ì •" @@ -2373,15 +2444,20 @@ msgstr "뮤트한 ê³„ì •" msgid "Muted accounts have their posts removed from your feed and from your notifications. Mutes are completely private." msgstr "ê³„ì •ì„ ë®¤íŠ¸í•˜ë©´ 피드와 알림ì—서 해당 ê³„ì •ì˜ ê²Œì‹œë¬¼ì´ ì‚¬ë¼ì§‘니다. 뮤트 목ë¡ì€ ì™„ì „ížˆ 비공개로 ìœ ì§€ë©ë‹ˆë‹¤." -#: src/view/screens/Moderation.tsx:100 +#: src/lib/moderation/useModerationCauseDescription.ts:85 +msgid "Muted by \"{0}\"" +msgstr "\"{0}\" ë‹˜ì´ ë®¤íŠ¸í•¨" + +#: src/screens/Moderation/index.tsx:234 msgid "Muted words & tags" -msgstr "" +msgstr "뮤트한 단어 ë° íƒœê·¸" -#: src/view/screens/ProfileList.tsx:277 +#: src/view/screens/ProfileList.tsx:621 msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them." msgstr "뮤트 목ë¡ì€ 비공개입니다. 뮤트한 ê³„ì •ì€ ë‚˜ì™€ ìƒí˜¸ìž‘ìš©í• ìˆ˜ 있지만 해당 ê³„ì •ì˜ ê²Œì‹œë¬¼ì„ ë³´ê±°ë‚˜ 해당 ê³„ì •ìœ¼ë¡œë¶€í„° ì•Œë¦¼ì„ ë°›ì„ ìˆ˜ 없습니다." -#: src/view/com/modals/BirthDateSettings.tsx:56 +#: src/components/dialogs/BirthDateSettings.tsx:34 +#: src/components/dialogs/BirthDateSettings.tsx:86 msgid "My Birthday" msgstr "ë‚´ ìƒë…„ì›”ì¼" @@ -2393,13 +2469,13 @@ msgstr "ë‚´ 피드" msgid "My Profile" msgstr "ë‚´ 프로필" -#: src/view/screens/Settings/index.tsx:582 +#: src/view/screens/Settings/index.tsx:600 msgid "My Saved Feeds" msgstr "ë‚´ ì €ìž¥ëœ í”¼ë“œ" #: src/view/com/auth/server-input/index.tsx:118 msgid "my-server.com" -msgstr "" +msgstr "my-server.com" #: src/view/com/modals/AddAppPasswords.tsx:179 #: src/view/com/modals/CreateOrEditList.tsx:290 @@ -2410,6 +2486,12 @@ msgstr "ì´ë¦„" msgid "Name is required" msgstr "ì´ë¦„ì„ ìž…ë ¥í•˜ì„¸ìš”" +#: src/lib/moderation/useReportOptions.ts:57 +#: src/lib/moderation/useReportOptions.ts:78 +#: src/lib/moderation/useReportOptions.ts:86 +msgid "Name or Description Violates Community Standards" +msgstr "ì´ë¦„ ë˜ëŠ” ì„¤ëª…ì´ ì»¤ë®¤ë‹ˆí‹° ê¸°ì¤€ì„ ìœ„ë°˜í•¨" + #: src/screens/Onboarding/index.tsx:25 msgid "Nature" msgstr "ìžì—°" @@ -2426,6 +2508,10 @@ msgstr "ë‹¤ìŒ í™”ë©´ìœ¼ë¡œ ì´ë™í•©ë‹ˆë‹¤" msgid "Navigates to your profile" msgstr "ë‚´ 프로필로 ì´ë™í•©ë‹ˆë‹¤" +#: src/components/ReportDialog/SelectReportOptionView.tsx:123 +msgid "Need to report a copyright violation?" +msgstr "ì €ìž‘ê¶Œ ìœ„ë°˜ì„ ì‹ ê³ í•´ì•¼ 하나요?" + #: src/view/com/modals/EmbedConsent.tsx:107 #: src/view/com/modals/EmbedConsent.tsx:123 msgid "Never load embeds from {0}" @@ -2434,15 +2520,11 @@ msgstr "{0}ì—서 ìž„ë² ë“œë¥¼ 불러오지 않습니다" #: src/view/com/auth/onboarding/WelcomeDesktop.tsx:72 #: src/view/com/auth/onboarding/WelcomeMobile.tsx:72 msgid "Never lose access to your followers and data." -msgstr "팔로워와 ë°ì´í„°ì— 대한 ì ‘ê·¼ ê¶Œí•œì„ ìžƒì§€ 않습니다." +msgstr "팔로워와 ë°ì´í„°ì— 대한 ì ‘ê·¼ ê¶Œí•œì„ ìžƒì§€ 마세요." #: src/screens/Onboarding/StepFinished.tsx:119 msgid "Never lose access to your followers or data." -msgstr "팔로워 ë˜ëŠ” ë°ì´í„°ì— 대한 ì ‘ê·¼ ê¶Œí•œì„ ìžƒì§€ 않습니다." - -#: src/components/dialogs/MutedWords.tsx:244 -msgid "Nevermind" -msgstr "" +msgstr "팔로워 ë˜ëŠ” ë°ì´í„°ì— 대한 ì ‘ê·¼ ê¶Œí•œì„ ìžƒì§€ 마세요." #: src/view/screens/Lists.tsx:76 msgctxt "action" @@ -2463,7 +2545,7 @@ msgstr "새 비밀번호" #: src/view/com/modals/ChangePassword.tsx:215 msgid "New Password" -msgstr "" +msgstr "새 비밀번호" #: src/view/com/feeds/FeedPage.tsx:126 msgctxt "action" @@ -2472,10 +2554,10 @@ msgstr "새 게시물" #: src/view/screens/Feeds.tsx:555 #: src/view/screens/Notifications.tsx:168 -#: src/view/screens/Profile.tsx:382 +#: src/view/screens/Profile.tsx:450 #: src/view/screens/ProfileFeed.tsx:433 -#: src/view/screens/ProfileList.tsx:196 -#: src/view/screens/ProfileList.tsx:224 +#: src/view/screens/ProfileList.tsx:199 +#: src/view/screens/ProfileList.tsx:227 #: src/view/shell/desktop/LeftNav.tsx:248 msgid "New post" msgstr "새 게시물" @@ -2527,12 +2609,12 @@ msgstr "ë‹¤ìŒ ì´ë¯¸ì§€" msgid "No" msgstr "아니요" -#: src/view/screens/ProfileFeed.tsx:584 -#: src/view/screens/ProfileList.tsx:754 +#: src/view/screens/ProfileFeed.tsx:561 +#: src/view/screens/ProfileList.tsx:769 msgid "No description" msgstr "설명 ì—†ìŒ" -#: src/view/com/profile/ProfileHeader.tsx:170 +#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:111 msgid "No longer following {0}" msgstr "ë” ì´ìƒ {0} ë‹˜ì„ íŒ”ë¡œìš°í•˜ì§€ 않ìŒ" @@ -2545,6 +2627,10 @@ msgstr "ì•„ì§ ì•Œë¦¼ì´ ì—†ìŠµë‹ˆë‹¤." msgid "No result" msgstr "ê²°ê³¼ ì—†ìŒ" +#: src/components/Lists.tsx:191 +msgid "No results found" +msgstr "결과를 ì°¾ì„ ìˆ˜ ì—†ìŒ" + #: src/view/screens/Feeds.tsx:495 msgid "No results found for \"{query}\"" msgstr "\"{query}\"ì— ëŒ€í•œ 결과를 ì°¾ì„ ìˆ˜ 없습니다" @@ -2563,12 +2649,21 @@ msgstr "괜찮습니다" msgid "Nobody" msgstr "ì—†ìŒ" +#: src/components/LikedByList.tsx:102 +#: src/components/LikesDialog.tsx:99 +msgid "Nobody has liked this yet. Maybe you should be the first!" +msgstr "ì•„ì§ ì•„ë¬´ë„ ì¢‹ì•„ìš”ë¥¼ 누르지 않았습니다. 첫 번째가 ë˜ì–´ 보세요!" + +#: src/lib/moderation/useGlobalLabelStrings.ts:42 +msgid "Non-sexual Nudity" +msgstr "ì„ ì •ì ì´ì§€ ì•Šì€ ë…¸ì¶œ" + #: src/view/com/modals/SelfLabel.tsx:135 msgid "Not Applicable." msgstr "해당 ì—†ìŒ." -#: src/Navigation.tsx:105 -#: src/view/screens/Profile.tsx:106 +#: src/Navigation.tsx:109 +#: src/view/screens/Profile.tsx:97 msgid "Not Found" msgstr "ì°¾ì„ ìˆ˜ ì—†ìŒ" @@ -2577,14 +2672,19 @@ msgstr "ì°¾ì„ ìˆ˜ ì—†ìŒ" msgid "Not right now" msgstr "ë‚˜ì¤‘ì— í•˜ê¸°" -#: src/view/screens/Moderation.tsx:252 +#: src/view/com/profile/ProfileMenu.tsx:368 +#: src/view/com/util/forms/PostDropdownBtn.tsx:342 +msgid "Note about sharing" +msgstr "ê³µìœ ê´€ë ¨ ì°¸ê³ ì‚¬í•" + +#: src/screens/Moderation/index.tsx:546 msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites." msgstr "ì°¸ê³ : Bluesky는 개방형 공개 네트워í¬ìž…니다. ì´ ì„¤ì •ì€ Bluesky 앱과 웹사ì´íЏì—서만 ë‚´ 콘í…ì¸ ê°€ 표시ë˜ëŠ” ê²ƒì„ ì œí•œí•˜ë©°, 다른 앱ì—서는 ì´ ì„¤ì •ì„ ì¤€ìˆ˜í•˜ì§€ ì•Šì„ ìˆ˜ 있습니다. 다른 앱과 웹사ì´íЏì—서는 로그아웃한 사용ìžì—게 ë‚´ 콘í…ì¸ ê°€ ê³„ì† í‘œì‹œë 수 있습니다." -#: src/Navigation.tsx:450 +#: src/Navigation.tsx:469 #: src/view/screens/Notifications.tsx:124 #: src/view/screens/Notifications.tsx:148 -#: src/view/shell/bottom-bar/BottomBar.tsx:205 +#: src/view/shell/bottom-bar/BottomBar.tsx:207 #: src/view/shell/desktop/LeftNav.tsx:361 #: src/view/shell/Drawer.tsx:435 #: src/view/shell/Drawer.tsx:436 @@ -2595,9 +2695,17 @@ msgstr "알림" msgid "Nudity" msgstr "노출" -#: src/view/com/util/ErrorBoundary.tsx:35 +#: src/lib/moderation/useReportOptions.ts:71 +msgid "Nudity or pornography not labeled as such" +msgstr "누드 ë˜ëŠ” ìŒëž€ë¬¼ë¡œ ì„¤ì •ë˜ì§€ ì•Šì€ ì½˜í…ì¸ " + +#: src/lib/moderation/useLabelBehaviorDescription.ts:11 +msgid "Off" +msgstr "ë„기" + +#: src/view/com/util/ErrorBoundary.tsx:49 msgid "Oh no!" -msgstr "안 ë¼!" +msgstr "ì´ëŸ°!" #: src/screens/Onboarding/StepInterests/index.tsx:128 msgid "Oh no! Something went wrong." @@ -2611,11 +2719,11 @@ msgstr "확ì¸" msgid "Oldest replies first" msgstr "ì˜¤ëž˜ëœ ìˆœ" -#: src/view/screens/Settings/index.tsx:234 +#: src/view/screens/Settings/index.tsx:240 msgid "Onboarding reset" msgstr "온보딩 ìž¬ì„¤ì •" -#: src/view/com/composer/Composer.tsx:382 +#: src/view/com/composer/Composer.tsx:391 msgid "One or more images is missing alt text." msgstr "하나 ì´ìƒì˜ ì´ë¯¸ì§€ì— 대체 í…스트가 누ë½ë˜ì—ˆìŠµë‹ˆë‹¤." @@ -2623,8 +2731,13 @@ msgstr "하나 ì´ìƒì˜ ì´ë¯¸ì§€ì— 대체 í…스트가 누ë½ë˜ì—ˆìŠµë‹ˆë‹¤. msgid "Only {0} can reply." msgstr "{0}ë§Œ ë‹µê¸€ì„ ë‹¬ 수 있습니다." -#: src/view/screens/AppPasswords.tsx:65 -#: src/view/screens/Profile.tsx:106 +#: src/components/Lists.tsx:81 +msgid "Oops, something went wrong!" +msgstr "ì´ëŸ°, ë”ê°€ 잘못ë˜ì—ˆìŠµë‹ˆë‹¤!" + +#: src/components/Lists.tsx:187 +#: src/view/screens/AppPasswords.tsx:67 +#: src/view/screens/Profile.tsx:97 msgid "Oops!" msgstr "ì´ëŸ°!" @@ -2632,28 +2745,33 @@ msgstr "ì´ëŸ°!" msgid "Open" msgstr "공개성" -#: src/view/screens/Moderation.tsx:75 -msgid "Open content filtering settings" -msgstr "" - -#: src/view/com/composer/Composer.tsx:477 -#: src/view/com/composer/Composer.tsx:478 +#: src/view/com/composer/Composer.tsx:486 +#: src/view/com/composer/Composer.tsx:487 msgid "Open emoji picker" msgstr "ì´ëª¨í‹°ì½˜ ì„ íƒê¸° 열기" -#: src/view/screens/Settings/index.tsx:712 +#: src/view/screens/ProfileFeed.tsx:299 +msgid "Open feed options menu" +msgstr "피드 옵션 메뉴 열기" + +#: src/view/screens/Settings/index.tsx:730 msgid "Open links with in-app browser" -msgstr "ë§í¬ë¥¼ ì¸ì•± 브ë¼ìš°ì €ë¡œ 엽니다" +msgstr "ë§í¬ë¥¼ ì¸ì•± 브ë¼ìš°ì €ë¡œ 열기" -#: src/view/screens/Moderation.tsx:92 -msgid "Open muted words settings" -msgstr "" +#: src/screens/Moderation/index.tsx:230 +msgid "Open muted words and tags settings" +msgstr "뮤트한 단어 ë° íƒœê·¸ ì„¤ì • 열기" -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:49 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:50 msgid "Open navigation" msgstr "내비게ì´ì…˜ 열기" -#: src/view/screens/Settings/index.tsx:804 +#: src/view/com/util/forms/PostDropdownBtn.tsx:183 +msgid "Open post options menu" +msgstr "게시물 옵션 메뉴 열기" + +#: src/view/screens/Settings/index.tsx:822 +#: src/view/screens/Settings/index.tsx:832 msgid "Open storybook page" msgstr "ìŠ¤í† ë¦¬ë¶ íŽ˜ì´ì§€ 열기" @@ -2669,7 +2787,7 @@ msgstr "디버그 í•ëª©ì— ëŒ€í•œ 추가 세부 ì •ë³´ë¥¼ 엽니다" msgid "Opens an expanded list of users in this notification" msgstr "ì´ ì•Œë¦¼ì—서 í™•ìž¥ëœ ì‚¬ìš©ìž ëª©ë¡ì„ 엽니다" -#: src/view/com/composer/photos/OpenCameraBtn.tsx:61 +#: src/view/com/composer/photos/OpenCameraBtn.tsx:78 msgid "Opens camera on device" msgstr "기기ì—서 ì¹´ë©”ë¼ë¥¼ 엽니다" @@ -2677,7 +2795,7 @@ msgstr "기기ì—서 ì¹´ë©”ë¼ë¥¼ 엽니다" msgid "Opens composer" msgstr "답글 작성 ìƒìžë¥¼ 엽니다" -#: src/view/screens/Settings/index.tsx:595 +#: src/view/screens/Settings/index.tsx:613 msgid "Opens configurable language settings" msgstr "구성 가능한 언어 ì„¤ì •ì„ ì—½ë‹ˆë‹¤" @@ -2685,31 +2803,15 @@ msgstr "구성 가능한 언어 ì„¤ì •ì„ ì—½ë‹ˆë‹¤" msgid "Opens device photo gallery" msgstr "ê¸°ê¸°ì˜ ì‚¬ì§„ 갤러리를 엽니다" -#: src/view/com/profile/ProfileHeader.tsx:420 -msgid "Opens editor for profile display name, avatar, background image, and description" -msgstr "프로필 표시 ì´ë¦„, 아바타, ë°°ê²½ ì´ë¯¸ì§€ ë° ì„¤ëª… 편집기를 엽니다" - -#: src/view/screens/Settings/index.tsx:649 +#: src/view/screens/Settings/index.tsx:667 msgid "Opens external embeds settings" msgstr "외부 ìž„ë² ë“œ ì„¤ì •ì„ ì—½ë‹ˆë‹¤" -#: src/view/com/profile/ProfileHeader.tsx:575 -msgid "Opens followers list" -msgstr "팔로워 목ë¡ì„ 엽니다" - -#: src/view/com/profile/ProfileHeader.tsx:594 -msgid "Opens following list" -msgstr "팔로우 중 목ë¡ì„ 엽니다" - -#: src/view/screens/Settings.tsx:412 -#~ msgid "Opens invite code list" -#~ msgstr "초대 코드 목ë¡ì„ 엽니다" - #: src/view/com/modals/InviteCodes.tsx:172 msgid "Opens list of invite codes" msgstr "초대 코드 목ë¡ì„ 엽니다" -#: src/view/screens/Settings/index.tsx:774 +#: src/view/screens/Settings/index.tsx:792 msgid "Opens modal for account deletion confirmation. Requires email code." msgstr "ê³„ì • ì‚ì œ 확ì¸ì„ 위한 대화 ìƒìžë¥¼ 엽니다. ì´ë©”ì¼ ì½”ë“œê°€ 필요합니다" @@ -2717,7 +2819,7 @@ msgstr "ê³„ì • ì‚ì œ 확ì¸ì„ 위한 대화 ìƒìžë¥¼ 엽니다. ì´ë©”ì¼ ì½” msgid "Opens modal for using custom domain" msgstr "ì‚¬ìš©ìž ì§€ì • ë„ë©”ì¸ì„ 사용하기 위한 대화 ìƒìžë¥¼ 엽니다" -#: src/view/screens/Settings/index.tsx:620 +#: src/view/screens/Settings/index.tsx:638 msgid "Opens moderation settings" msgstr "ê²€í† ì„¤ì •ì„ ì—½ë‹ˆë‹¤" @@ -2725,32 +2827,33 @@ msgstr "ê²€í† ì„¤ì •ì„ ì—½ë‹ˆë‹¤" msgid "Opens password reset form" msgstr "비밀번호 ìž¬ì„¤ì • ì–‘ì‹ì„ 엽니다" -#: src/view/com/home/HomeHeaderLayout.web.tsx:60 +#: src/view/com/home/HomeHeaderLayout.web.tsx:63 #: src/view/screens/Feeds.tsx:356 msgid "Opens screen to edit Saved Feeds" msgstr "ì €ìž¥ëœ í”¼ë“œë¥¼ íŽ¸ì§‘í• ìˆ˜ 있는 í™”ë©´ì„ ì—½ë‹ˆë‹¤" -#: src/view/screens/Settings/index.tsx:576 +#: src/view/screens/Settings/index.tsx:594 msgid "Opens screen with all saved feeds" msgstr "ëª¨ë“ ì €ìž¥ëœ í”¼ë“œ í™”ë©´ì„ ì—½ë‹ˆë‹¤" -#: src/view/screens/Settings/index.tsx:676 +#: src/view/screens/Settings/index.tsx:694 msgid "Opens the app password settings page" msgstr "비밀번호 ì„¤ì • 페ì´ì§€ë¥¼ 엽니다" -#: src/view/screens/Settings/index.tsx:535 +#: src/view/screens/Settings/index.tsx:553 msgid "Opens the home feed preferences" msgstr "홈 피드 ì„¤ì •ì„ ì—½ë‹ˆë‹¤" -#: src/view/screens/Settings/index.tsx:805 +#: src/view/screens/Settings/index.tsx:823 +#: src/view/screens/Settings/index.tsx:833 msgid "Opens the storybook page" msgstr "ìŠ¤í† ë¦¬ë¶ íŽ˜ì´ì§€ë¥¼ 엽니다" -#: src/view/screens/Settings/index.tsx:793 +#: src/view/screens/Settings/index.tsx:811 msgid "Opens the system log page" msgstr "시스템 로그 페ì´ì§€ë¥¼ 엽니다" -#: src/view/screens/Settings/index.tsx:556 +#: src/view/screens/Settings/index.tsx:574 msgid "Opens the threads preferences" msgstr "ìŠ¤ë ˆë“œ ì„¤ì •ì„ ì—½ë‹ˆë‹¤" @@ -2758,22 +2861,27 @@ msgstr "ìŠ¤ë ˆë“œ ì„¤ì •ì„ ì—½ë‹ˆë‹¤" msgid "Option {0} of {numItems}" msgstr "{numItems}ê°œ 중 {0}번째 옵션" +#: src/components/ReportDialog/SubmitView.tsx:162 +msgid "Optionally provide additional information below:" +msgstr "ì„ íƒ ì‚¬í•으로 ì•„ëž˜ì— ì¶”ê°€ ì •ë³´ë¥¼ ìž…ë ¥í•©ë‹ˆë‹¤:" + #: src/view/com/modals/Threadgate.tsx:89 msgid "Or combine these options:" msgstr "ë˜ëŠ” ë‹¤ìŒ ì˜µì…˜ì„ ê²°í•©í•˜ì„¸ìš”:" +#: src/lib/moderation/useReportOptions.ts:25 +msgid "Other" +msgstr "기타" + #: src/view/com/auth/login/ChooseAccountForm.tsx:138 msgid "Other account" msgstr "다른 ê³„ì •" -#: src/view/com/modals/ServerInput.tsx:88 -#~ msgid "Other service" -#~ msgstr "다른 서비스" - #: src/view/com/composer/select-language/SelectLangBtn.tsx:91 msgid "Other..." msgstr "기타…" +#: src/components/Lists.tsx:193 #: src/view/screens/NotFound.tsx:45 msgid "Page not found" msgstr "페ì´ì§€ë¥¼ ì°¾ì„ ìˆ˜ ì—†ìŒ" @@ -2782,8 +2890,8 @@ msgstr "페ì´ì§€ë¥¼ ì°¾ì„ ìˆ˜ ì—†ìŒ" msgid "Page Not Found" msgstr "페ì´ì§€ë¥¼ ì°¾ì„ ìˆ˜ ì—†ìŒ" -#: src/view/com/auth/create/Step1.tsx:214 -#: src/view/com/auth/create/Step1.tsx:224 +#: src/view/com/auth/create/Step1.tsx:191 +#: src/view/com/auth/create/Step1.tsx:201 #: src/view/com/auth/login/LoginForm.tsx:226 #: src/view/com/auth/login/SetNewPasswordForm.tsx:161 #: src/view/com/modals/DeleteAccount.tsx:202 @@ -2798,11 +2906,11 @@ msgstr "비밀번호 변경ë¨" msgid "Password updated!" msgstr "비밀번호 변경ë¨" -#: src/Navigation.tsx:160 +#: src/Navigation.tsx:164 msgid "People followed by @{0}" msgstr "@{0} ë‹˜ì´ íŒ”ë¡œìš°í•œ 사람들" -#: src/Navigation.tsx:153 +#: src/Navigation.tsx:157 msgid "People following @{0}" msgstr "@{0} ë‹˜ì„ íŒ”ë¡œìš°í•˜ëŠ” 사람들" @@ -2818,19 +2926,19 @@ msgstr "ì•¨ë²”ì— ì ‘ê·¼í• ìˆ˜ 있는 ê¶Œí•œì´ ê±°ë¶€ë˜ì—ˆìŠµë‹ˆë‹¤. ì‹œìŠ¤í… msgid "Pets" msgstr "ë°˜ë ¤ë™ë¬¼" -#: src/view/com/auth/create/Step2.tsx:183 -#~ msgid "Phone number" -#~ msgstr "ì „í™”ë²ˆí˜¸" - #: src/view/com/modals/SelfLabel.tsx:121 msgid "Pictures meant for adults." msgstr "성ì¸ìš© 사진." -#: src/view/screens/ProfileFeed.tsx:354 -#: src/view/screens/ProfileList.tsx:581 +#: src/view/screens/ProfileFeed.tsx:291 +#: src/view/screens/ProfileList.tsx:563 msgid "Pin to home" msgstr "í™ˆì— ê³ ì •" +#: src/view/screens/ProfileFeed.tsx:294 +msgid "Pin to Home" +msgstr "í™ˆì— ê³ ì •" + #: src/view/screens/SavedFeeds.tsx:88 msgid "Pinned Feeds" msgstr "ê³ ì •ëœ í”¼ë“œ" @@ -2858,7 +2966,7 @@ msgstr "비밀번호를 ìž…ë ¥í•˜ì„¸ìš”." #: src/view/com/auth/create/state.ts:131 msgid "Please complete the verification captcha." -msgstr "" +msgstr "ì¸ì¦ 캡차를 완료해 주세요." #: src/view/com/modals/ChangeEmail.tsx:67 msgid "Please confirm your email before changing it. This is a temporary requirement while email-updating tools are added, and it will soon be removed." @@ -2868,21 +2976,13 @@ msgstr "ì´ë©”ì¼ì„ 변경하기 ì „ì— ì´ë©”ì¼ì„ 확ì¸í•´ 주세요. ì´ëŠ msgid "Please enter a name for your app password. All spaces is not allowed." msgstr "앱 ë¹„ë°€ë²ˆí˜¸ì˜ ì´ë¦„ì„ ìž…ë ¥í•˜ì„¸ìš”. ëª¨ë“ ê³µë°± 문ìžëŠ” 허용ë˜ì§€ 않습니다." -#: src/view/com/auth/create/Step2.tsx:206 -#~ msgid "Please enter a phone number that can receive SMS text messages." -#~ msgstr "SMS ë¬¸ìž ë©”ì‹œì§€ë¥¼ ë°›ì„ ìˆ˜ 있는 íœ´ëŒ€í° ë²ˆí˜¸ë¥¼ ìž…ë ¥í•˜ì„¸ìš”." - #: src/view/com/modals/AddAppPasswords.tsx:145 msgid "Please enter a unique name for this App Password or use our randomly generated one." msgstr "ì´ ì•± ë¹„ë°€ë²ˆí˜¸ì— ëŒ€í•´ ê³ ìœ í•œ ì´ë¦„ì„ ìž…ë ¥í•˜ê±°ë‚˜ 무작위로 ìƒì„±ëœ ì´ë¦„ì„ ì‚¬ìš©í•©ë‹ˆë‹¤." -#: src/view/com/auth/create/state.ts:170 -#~ msgid "Please enter the code you received by SMS." -#~ msgstr "SMS로 ë°›ì€ ì½”ë“œë¥¼ ìž…ë ¥í•˜ì„¸ìš”." - -#: src/view/com/auth/create/Step2.tsx:282 -#~ msgid "Please enter the verification code sent to {phoneNumberFormatted}." -#~ msgstr "{phoneNumberFormatted}(으)로 ë³´ë‚´ì§„ ì¸ì¦ 코드를 ìž…ë ¥í•˜ì„¸ìš”." +#: src/components/dialogs/MutedWords.tsx:68 +msgid "Please enter a valid word, tag, or phrase to mute" +msgstr "ë®¤íŠ¸í• ë‹¨ì–´ë‚˜ 태그 ë˜ëŠ” 문구를 ìž…ë ¥í•˜ì„¸ìš”" #: src/view/com/auth/create/state.ts:103 msgid "Please enter your email." @@ -2892,16 +2992,15 @@ msgstr "ì´ë©”ì¼ì„ ìž…ë ¥í•˜ì„¸ìš”." msgid "Please enter your password as well:" msgstr "ë¹„ë°€ë²ˆí˜¸ë„ ìž…ë ¥í•´ 주세요:" -#: src/view/com/modals/AppealLabel.tsx:72 -#: src/view/com/modals/AppealLabel.tsx:75 -msgid "Please tell us why you think this content warning was incorrectly applied!" -msgstr "ì´ ì½˜í…ì¸ ê²½ê³ ê°€ 잘못 ì ìš©ë˜ì—ˆë‹¤ê³ ìƒê°í•˜ëŠ” ì´ìœ 를 ì•Œë ¤ì£¼ì„¸ìš”!" +#: src/components/moderation/LabelsOnMeDialog.tsx:222 +msgid "Please explain why you think this label was incorrectly applied by {0}" +msgstr "{0}ì´(ê°€) ì´ ë¼ë²¨ì„ 잘못 ì ìš©í–ˆë‹¤ê³ ìƒê°í•˜ëŠ” ì´ìœ 를 설명해 주세요" #: src/view/com/modals/VerifyEmail.tsx:101 msgid "Please Verify Your Email" msgstr "ì´ë©”ì¼ ì¸ì¦í•˜ê¸°" -#: src/view/com/composer/Composer.tsx:222 +#: src/view/com/composer/Composer.tsx:221 msgid "Please wait for your link card to finish loading" msgstr "ë§í¬ 카드를 ì™„ì „ížˆ 불러올 때까지 ê¸°ë‹¤ë ¤ì£¼ì„¸ìš”" @@ -2911,15 +3010,19 @@ msgstr "ì •ì¹˜" #: src/view/com/modals/SelfLabel.tsx:111 msgid "Porn" -msgstr "í¬ë¥´ë…¸" +msgstr "ìŒëž€ë¬¼" + +#: src/lib/moderation/useGlobalLabelStrings.ts:34 +msgid "Pornography" +msgstr "ìŒëž€ë¬¼" -#: src/view/com/composer/Composer.tsx:357 -#: src/view/com/composer/Composer.tsx:365 +#: src/view/com/composer/Composer.tsx:366 +#: src/view/com/composer/Composer.tsx:374 msgctxt "action" msgid "Post" msgstr "게시하기" -#: src/view/com/post-thread/PostThread.tsx:303 +#: src/view/com/post-thread/PostThread.tsx:304 msgctxt "description" msgid "Post" msgstr "게시물" @@ -2928,20 +3031,30 @@ msgstr "게시물" msgid "Post by {0}" msgstr "{0} ë‹˜ì˜ ê²Œì‹œë¬¼" -#: src/Navigation.tsx:172 -#: src/Navigation.tsx:179 -#: src/Navigation.tsx:186 +#: src/Navigation.tsx:176 +#: src/Navigation.tsx:183 +#: src/Navigation.tsx:190 msgid "Post by @{0}" msgstr "@{0} ë‹˜ì˜ ê²Œì‹œë¬¼" -#: src/view/com/util/forms/PostDropdownBtn.tsx:90 +#: src/view/com/util/forms/PostDropdownBtn.tsx:105 msgid "Post deleted" msgstr "게시물 ì‚ì œë¨" -#: src/view/com/post-thread/PostThread.tsx:462 +#: src/view/com/post-thread/PostThread.tsx:463 msgid "Post hidden" msgstr "게시물 숨김" +#: src/components/moderation/ModerationDetailsDialog.tsx:98 +#: src/lib/moderation/useModerationCauseDescription.ts:99 +msgid "Post Hidden by Muted Word" +msgstr "뮤트한 단어로 숨겨진 게시물" + +#: src/components/moderation/ModerationDetailsDialog.tsx:101 +#: src/lib/moderation/useModerationCauseDescription.ts:108 +msgid "Post Hidden by You" +msgstr "ë‚´ê°€ 숨긴 게시물" + #: src/view/com/composer/select-language/SelectLangBtn.tsx:87 msgid "Post language" msgstr "게시물 언어" @@ -2950,21 +3063,21 @@ msgstr "게시물 언어" msgid "Post Languages" msgstr "게시물 언어" -#: src/view/com/post-thread/PostThread.tsx:514 +#: src/view/com/post-thread/PostThread.tsx:515 msgid "Post not found" msgstr "ê²Œì‹œë¬¼ì„ ì°¾ì„ ìˆ˜ ì—†ìŒ" -#: src/components/TagMenu/index.tsx:257 +#: src/components/TagMenu/index.tsx:253 msgid "posts" -msgstr "" +msgstr "게시물" -#: src/view/screens/Profile.tsx:180 +#: src/view/screens/Profile.tsx:188 msgid "Posts" msgstr "게시물" -#: src/components/dialogs/MutedWords.tsx:77 +#: src/components/dialogs/MutedWords.tsx:90 msgid "Posts can be muted based on their text, their tags, or both." -msgstr "" +msgstr "ê²Œì‹œë¬¼ì˜ ê¸€ ë° íƒœê·¸ì— ë”°ë¼ ê²Œì‹œë¬¼ì„ ë®¤íŠ¸í• ìˆ˜ 있습니다." #: src/view/com/posts/FeedErrorMessage.tsx:64 msgid "Posts hidden" @@ -2986,14 +3099,14 @@ msgstr "주 언어" msgid "Prioritize Your Follows" msgstr "ë‚´ 팔로우 ë¨¼ì € 표시" -#: src/view/screens/Settings/index.tsx:632 +#: src/view/screens/Settings/index.tsx:650 #: src/view/shell/desktop/RightNav.tsx:72 msgid "Privacy" msgstr "ê°œì¸ì •ë³´" -#: src/Navigation.tsx:217 +#: src/Navigation.tsx:231 #: src/view/screens/PrivacyPolicy.tsx:29 -#: src/view/screens/Settings/index.tsx:891 +#: src/view/screens/Settings/index.tsx:919 #: src/view/shell/Drawer.tsx:262 msgid "Privacy Policy" msgstr "ê°œì¸ì •ë³´ 처리방침" @@ -3002,7 +3115,12 @@ msgstr "ê°œì¸ì •ë³´ 처리방침" msgid "Processing..." msgstr "처리 중…" -#: src/view/shell/bottom-bar/BottomBar.tsx:247 +#: src/view/screens/DebugMod.tsx:888 +#: src/view/screens/Profile.tsx:340 +msgid "profile" +msgstr "프로필" + +#: src/view/shell/bottom-bar/BottomBar.tsx:249 #: src/view/shell/desktop/LeftNav.tsx:415 #: src/view/shell/Drawer.tsx:70 #: src/view/shell/Drawer.tsx:546 @@ -3014,7 +3132,7 @@ msgstr "프로필" msgid "Profile updated" msgstr "프로필 ì—…ë°ì´íЏë¨" -#: src/view/screens/Settings/index.tsx:949 +#: src/view/screens/Settings/index.tsx:977 msgid "Protect your account by verifying your email." msgstr "ì´ë©”ì¼ì„ ì¸ì¦í•˜ì—¬ ê³„ì •ì„ ë³´í˜¸í•˜ì„¸ìš”." @@ -3030,11 +3148,11 @@ msgstr "ì¼ê´„ 뮤트하거나 ì°¨ë‹¨í• ìˆ˜ 있는 공개ì ì´ê³ ê³µìœ ê°€ëŠ msgid "Public, shareable lists which can drive feeds." msgstr "피드를 íƒìƒ‰í• 수 있는 공개ì ì´ê³ ê³µìœ ê°€ëŠ¥í•œ 목ë¡ìž…니다." -#: src/view/com/composer/Composer.tsx:342 +#: src/view/com/composer/Composer.tsx:351 msgid "Publish post" msgstr "게시물 게시하기" -#: src/view/com/composer/Composer.tsx:342 +#: src/view/com/composer/Composer.tsx:351 msgid "Publish reply" msgstr "답글 게시하기" @@ -3068,36 +3186,46 @@ msgstr "추천 피드" msgid "Recommended Users" msgstr "추천 사용ìž" -#: src/components/dialogs/MutedWords.tsx:249 +#: src/components/dialogs/MutedWords.tsx:287 +#: src/view/com/feeds/FeedSourceCard.tsx:283 #: src/view/com/modals/ListAddRemoveUsers.tsx:264 #: src/view/com/modals/SelfLabel.tsx:83 #: src/view/com/modals/UserAddRemoveLists.tsx:219 -#: src/view/com/util/UserAvatar.tsx:285 -#: src/view/com/util/UserBanner.tsx:91 +#: src/view/com/posts/FeedErrorMessage.tsx:204 msgid "Remove" msgstr "ì œê±°" -#: src/view/com/feeds/FeedSourceCard.tsx:108 -msgid "Remove {0} from my feeds?" -msgstr "{0}ì„(를) ë‚´ 피드ì—서 ì œê±°í•˜ì‹œê² ìŠµë‹ˆê¹Œ?" - #: src/view/com/util/AccountDropdownBtn.tsx:22 msgid "Remove account" msgstr "ê³„ì • ì œê±°" -#: src/view/com/posts/FeedErrorMessage.tsx:131 -#: src/view/com/posts/FeedErrorMessage.tsx:166 +#: src/view/com/util/UserAvatar.tsx:351 +msgid "Remove Avatar" +msgstr "아바타 ì œê±°" + +#: src/view/com/util/UserBanner.tsx:145 +msgid "Remove Banner" +msgstr "배너 ì œê±°" + +#: src/view/com/posts/FeedErrorMessage.tsx:160 msgid "Remove feed" msgstr "피드 ì œê±°" -#: src/view/com/feeds/FeedSourceCard.tsx:107 -#: src/view/com/feeds/FeedSourceCard.tsx:169 -#: src/view/com/feeds/FeedSourceCard.tsx:174 -#: src/view/com/feeds/FeedSourceCard.tsx:245 -#: src/view/screens/ProfileFeed.tsx:273 +#: src/view/com/posts/FeedErrorMessage.tsx:201 +msgid "Remove feed?" +msgstr "피드를 ì œê±°í•˜ì‹œê² ìŠµë‹ˆê¹Œ?" + +#: src/view/com/feeds/FeedSourceCard.tsx:173 +#: src/view/com/feeds/FeedSourceCard.tsx:233 +#: src/view/screens/ProfileFeed.tsx:334 +#: src/view/screens/ProfileFeed.tsx:340 msgid "Remove from my feeds" msgstr "ë‚´ 피드ì—서 ì œê±°" +#: src/view/com/feeds/FeedSourceCard.tsx:278 +msgid "Remove from my feeds?" +msgstr "ë‚´ 피드ì—서 ì œê±°í•˜ì‹œê² ìŠµë‹ˆê¹Œ?" + #: src/view/com/composer/photos/Gallery.tsx:167 msgid "Remove image" msgstr "ì´ë¯¸ì§€ ì œê±°" @@ -3106,37 +3234,36 @@ msgstr "ì´ë¯¸ì§€ ì œê±°" msgid "Remove image preview" msgstr "ì´ë¯¸ì§€ 미리보기 ì œê±°" -#: src/components/dialogs/MutedWords.tsx:294 +#: src/components/dialogs/MutedWords.tsx:330 msgid "Remove mute word from your list" -msgstr "" +msgstr "목ë¡ì—서 뮤트한 단어 ì œê±°" #: src/view/com/modals/Repost.tsx:47 msgid "Remove repost" msgstr "재게시를 취소합니다" -#: src/view/com/feeds/FeedSourceCard.tsx:175 -msgid "Remove this feed from my feeds?" -msgstr "ì´ í”¼ë“œë¥¼ ë‚´ 피드ì—서 ì œê±°í•˜ì‹œê² ìŠµë‹ˆê¹Œ?" - -#: src/view/com/posts/FeedErrorMessage.tsx:132 -msgid "Remove this feed from your saved feeds?" -msgstr "ì´ í”¼ë“œë¥¼ ì €ìž¥ëœ í”¼ë“œì—서 ì œê±°í•˜ì‹œê² ìŠµë‹ˆê¹Œ?" +#: src/view/com/posts/FeedErrorMessage.tsx:202 +msgid "Remove this feed from your saved feeds" +msgstr "ì €ìž¥ëœ í”¼ë“œì—서 ì´ í”¼ë“œë¥¼ ì œê±°í•©ë‹ˆë‹¤" #: src/view/com/modals/ListAddRemoveUsers.tsx:199 #: src/view/com/modals/UserAddRemoveLists.tsx:152 msgid "Removed from list" msgstr "리스트ì—서 ì œê±°ë¨" -#: src/view/com/feeds/FeedSourceCard.tsx:113 -#: src/view/com/feeds/FeedSourceCard.tsx:180 +#: src/view/com/feeds/FeedSourceCard.tsx:121 msgid "Removed from my feeds" msgstr "ë‚´ 피드ì—서 ì œê±°ë¨" +#: src/view/screens/ProfileFeed.tsx:208 +msgid "Removed from your feeds" +msgstr "ë‚´ 피드ì—서 ì œê±°ë¨" + #: src/view/com/composer/ExternalEmbed.tsx:71 msgid "Removes default thumbnail from {0}" msgstr "{0}ì—서 기본 미리보기 ì´ë¯¸ì§€ë¥¼ ì œê±°í•©ë‹ˆë‹¤" -#: src/view/screens/Profile.tsx:181 +#: src/view/screens/Profile.tsx:189 msgid "Replies" msgstr "답글" @@ -3144,7 +3271,7 @@ msgstr "답글" msgid "Replies to this thread are disabled" msgstr "ì´ ìŠ¤ë ˆë“œì— ëŒ€í•œ ë‹µê¸€ì´ ë¹„í™œì„±í™”ë©ë‹ˆë‹¤." -#: src/view/com/composer/Composer.tsx:355 +#: src/view/com/composer/Composer.tsx:364 msgctxt "action" msgid "Reply" msgstr "답글" @@ -3153,33 +3280,51 @@ msgstr "답글" msgid "Reply Filters" msgstr "답글 í•„í„°" -#: src/view/com/post/Post.tsx:167 -#: src/view/com/posts/FeedItem.tsx:287 +#: src/view/com/post/Post.tsx:169 +#: src/view/com/posts/FeedItem.tsx:283 msgctxt "description" msgid "Reply to <0/>" msgstr "<0/> 님ì—게 보내는 답글" -#: src/view/com/modals/report/Modal.tsx:166 -msgid "Report {collectionName}" -msgstr "{collectionName} ì‹ ê³ " - -#: src/view/com/profile/ProfileHeader.tsx:361 +#: src/view/com/profile/ProfileMenu.tsx:319 +#: src/view/com/profile/ProfileMenu.tsx:322 msgid "Report Account" msgstr "ê³„ì • ì‹ ê³ " -#: src/view/screens/ProfileFeed.tsx:293 +#: src/view/screens/ProfileFeed.tsx:351 +#: src/view/screens/ProfileFeed.tsx:353 msgid "Report feed" msgstr "피드 ì‹ ê³ " -#: src/view/screens/ProfileList.tsx:459 +#: src/view/screens/ProfileList.tsx:429 msgid "Report List" msgstr "리스트 ì‹ ê³ " -#: src/view/com/modals/report/SendReportButton.tsx:37 -#: src/view/com/util/forms/PostDropdownBtn.tsx:255 +#: src/view/com/util/forms/PostDropdownBtn.tsx:292 +#: src/view/com/util/forms/PostDropdownBtn.tsx:294 msgid "Report post" msgstr "게시물 ì‹ ê³ " +#: src/components/ReportDialog/SelectReportOptionView.tsx:42 +msgid "Report this content" +msgstr "ì´ ì½˜í…ì¸ ì‹ ê³ í•˜ê¸°" + +#: src/components/ReportDialog/SelectReportOptionView.tsx:55 +msgid "Report this feed" +msgstr "ì´ í”¼ë“œ ì‹ ê³ í•˜ê¸°" + +#: src/components/ReportDialog/SelectReportOptionView.tsx:52 +msgid "Report this list" +msgstr "ì´ ë¦¬ìŠ¤íŠ¸ ì‹ ê³ í•˜ê¸°" + +#: src/components/ReportDialog/SelectReportOptionView.tsx:49 +msgid "Report this post" +msgstr "ì´ ê²Œì‹œë¬¼ ì‹ ê³ í•˜ê¸°" + +#: src/components/ReportDialog/SelectReportOptionView.tsx:46 +msgid "Report this user" +msgstr "ì´ ì‚¬ìš©ìž ì‹ ê³ í•˜ê¸°" + #: src/view/com/modals/Repost.tsx:43 #: src/view/com/modals/Repost.tsx:48 #: src/view/com/modals/Repost.tsx:53 @@ -3201,11 +3346,11 @@ msgstr "재게시 ë˜ëŠ” 게시물 ì¸ìš©" msgid "Reposted By" msgstr "재게시한 사용ìž" -#: src/view/com/posts/FeedItem.tsx:207 +#: src/view/com/posts/FeedItem.tsx:201 msgid "Reposted by {0}" msgstr "{0} ë‹˜ì´ ìž¬ê²Œì‹œí•¨" -#: src/view/com/posts/FeedItem.tsx:224 +#: src/view/com/posts/FeedItem.tsx:218 msgid "Reposted by <0/>" msgstr "<0/> ë‹˜ì´ ìž¬ê²Œì‹œí•¨" @@ -3213,7 +3358,7 @@ msgstr "<0/> ë‹˜ì´ ìž¬ê²Œì‹œí•¨" msgid "reposted your post" msgstr "ë‹˜ì´ ë‚´ ê²Œì‹œë¬¼ì„ ìž¬ê²Œì‹œí–ˆìŠµë‹ˆë‹¤" -#: src/view/com/post-thread/PostThreadItem.tsx:188 +#: src/view/com/post-thread/PostThreadItem.tsx:187 msgid "Reposts of this post" msgstr "ì´ ê²Œì‹œë¬¼ì˜ ìž¬ê²Œì‹œ" @@ -3222,20 +3367,16 @@ msgstr "ì´ ê²Œì‹œë¬¼ì˜ ìž¬ê²Œì‹œ" msgid "Request Change" msgstr "변경 ìš”ì²" -#: src/view/com/auth/create/Step2.tsx:219 -#~ msgid "Request code" -#~ msgstr "코드 ìš”ì²" - #: src/view/com/modals/ChangePassword.tsx:239 #: src/view/com/modals/ChangePassword.tsx:241 msgid "Request Code" -msgstr "" +msgstr "코드 ìš”ì²" -#: src/view/screens/Settings/index.tsx:456 +#: src/view/screens/Settings/index.tsx:474 msgid "Require alt text before posting" msgstr "게시하기 ì „ 대체 í…스트 필수" -#: src/view/com/auth/create/Step1.tsx:153 +#: src/view/com/auth/create/Step1.tsx:146 msgid "Required for this provider" msgstr "ì´ ì œê³µìžì—서 필수" @@ -3246,13 +3387,13 @@ msgstr "ìž¬ì„¤ì • 코드" #: src/view/com/modals/ChangePassword.tsx:190 msgid "Reset Code" -msgstr "" +msgstr "ìž¬ì„¤ì • 코드" -#: src/view/screens/Settings/index.tsx:824 +#: src/view/screens/Settings/index.tsx:852 msgid "Reset onboarding" msgstr "온보딩 초기화" -#: src/view/screens/Settings/index.tsx:827 +#: src/view/screens/Settings/index.tsx:855 msgid "Reset onboarding state" msgstr "온보딩 ìƒíƒœ 초기화" @@ -3260,19 +3401,19 @@ msgstr "온보딩 ìƒíƒœ 초기화" msgid "Reset password" msgstr "비밀번호 ìž¬ì„¤ì •" -#: src/view/screens/Settings/index.tsx:814 +#: src/view/screens/Settings/index.tsx:842 msgid "Reset preferences" msgstr "ì„¤ì • 초기화" -#: src/view/screens/Settings/index.tsx:817 +#: src/view/screens/Settings/index.tsx:845 msgid "Reset preferences state" msgstr "ì„¤ì • ìƒíƒœ 초기화" -#: src/view/screens/Settings/index.tsx:825 +#: src/view/screens/Settings/index.tsx:853 msgid "Resets the onboarding state" msgstr "온보딩 ìƒíƒœ 초기화" -#: src/view/screens/Settings/index.tsx:815 +#: src/view/screens/Settings/index.tsx:843 msgid "Resets the preferences state" msgstr "ì„¤ì • ìƒíƒœ 초기화" @@ -3296,17 +3437,16 @@ msgstr "오류가 ë°œìƒí•œ 마지막 ìž‘ì—…ì„ ë‹¤ì‹œ 시ë„합니다" msgid "Retry" msgstr "다시 시ë„" -#: src/view/com/auth/create/Step2.tsx:247 -#~ msgid "Retry." -#~ msgstr "다시 시ë„하기" - -#: src/view/screens/ProfileList.tsx:898 +#: src/view/screens/ProfileList.tsx:917 msgid "Return to previous page" msgstr "ì´ì „ 페ì´ì§€ë¡œ ëŒì•„갑니다" -#: src/view/shell/desktop/RightNav.tsx:55 -#~ msgid "SANDBOX. Posts and accounts are not permanent." -#~ msgstr "샌드박스. 글과 ê³„ì •ì€ ì˜êµ¬ì ì´ì§€ 않습니다." +#: src/components/dialogs/BirthDateSettings.tsx:118 +#: src/view/com/modals/ChangeHandle.tsx:173 +#: src/view/com/modals/CreateOrEditList.tsx:337 +#: src/view/com/modals/EditProfile.tsx:224 +msgid "Save" +msgstr "ì €ìž¥" #: src/view/com/lightbox/Lightbox.tsx:132 #: src/view/com/modals/CreateOrEditList.tsx:345 @@ -3314,19 +3454,14 @@ msgctxt "action" msgid "Save" msgstr "ì €ìž¥" -#: src/view/com/modals/BirthDateSettings.tsx:94 -#: src/view/com/modals/BirthDateSettings.tsx:97 -#: src/view/com/modals/ChangeHandle.tsx:173 -#: src/view/com/modals/CreateOrEditList.tsx:337 -#: src/view/com/modals/EditProfile.tsx:224 -#: src/view/screens/ProfileFeed.tsx:346 -msgid "Save" -msgstr "ì €ìž¥" - #: src/view/com/modals/AltImage.tsx:130 msgid "Save alt text" msgstr "대체 í…스트 ì €ìž¥" +#: src/components/dialogs/BirthDateSettings.tsx:112 +msgid "Save birthday" +msgstr "ìƒë…„ì›”ì¼ ì €ìž¥" + #: src/view/com/modals/EditProfile.tsx:232 msgid "Save Changes" msgstr "변경 ì‚¬í• ì €ìž¥" @@ -3339,10 +3474,19 @@ msgstr "핸들 변경 ì €ìž¥" msgid "Save image crop" msgstr "ì´ë¯¸ì§€ ìžë¥´ê¸° ì €ìž¥" +#: src/view/screens/ProfileFeed.tsx:335 +#: src/view/screens/ProfileFeed.tsx:341 +msgid "Save to my feeds" +msgstr "ë‚´ í”¼ë“œì— ì €ìž¥" + #: src/view/screens/SavedFeeds.tsx:122 msgid "Saved Feeds" msgstr "ì €ìž¥ëœ í”¼ë“œ" +#: src/view/screens/ProfileFeed.tsx:212 +msgid "Saved to your feeds" +msgstr "ë‚´ í”¼ë“œì— ì €ìž¥ë¨" + #: src/view/com/modals/EditProfile.tsx:225 msgid "Saves any changes to your profile" msgstr "í”„ë¡œí•„ì— ëŒ€í•œ ëª¨ë“ ë³€ê²½ 사í•ì„ ì €ìž¥í•©ë‹ˆë‹¤" @@ -3355,11 +3499,11 @@ msgstr "í•¸ë“¤ì„ {handle}(으)로 변경합니다" msgid "Science" msgstr "과학" -#: src/view/screens/ProfileList.tsx:854 +#: src/view/screens/ProfileList.tsx:873 msgid "Scroll to top" msgstr "맨 위로 스í¬ë¡¤" -#: src/Navigation.tsx:440 +#: src/Navigation.tsx:459 #: src/view/com/auth/LoggedOut.tsx:122 #: src/view/com/modals/ListAddRemoveUsers.tsx:75 #: src/view/com/util/forms/SearchInput.tsx:67 @@ -3367,7 +3511,7 @@ msgstr "맨 위로 스í¬ë¡¤" #: src/view/screens/Search/Search.tsx:419 #: src/view/screens/Search/Search.tsx:668 #: src/view/screens/Search/Search.tsx:686 -#: src/view/shell/bottom-bar/BottomBar.tsx:159 +#: src/view/shell/bottom-bar/BottomBar.tsx:161 #: src/view/shell/desktop/LeftNav.tsx:324 #: src/view/shell/desktop/Search.tsx:214 #: src/view/shell/desktop/Search.tsx:223 @@ -3382,12 +3526,12 @@ msgid "Search for \"{query}\"" msgstr "\"{query}\"ì— ëŒ€í•œ 검색 ê²°ê³¼" #: src/components/TagMenu/index.tsx:145 -msgid "Search for all posts by @{authorHandle} with tag {tag}" -msgstr "" +msgid "Search for all posts by @{authorHandle} with tag {displayTag}" +msgstr "{displayTag} 태그를 사용한 @{authorHandle} ë‹˜ì˜ ëª¨ë“ ê²Œì‹œë¬¼ 검색" -#: src/components/TagMenu/index.tsx:90 -msgid "Search for all posts with tag {tag}" -msgstr "" +#: src/components/TagMenu/index.tsx:94 +msgid "Search for all posts with tag {displayTag}" +msgstr "{displayTag} 태그를 사용한 ëª¨ë“ ê²Œì‹œë¬¼ 검색" #: src/view/com/auth/LoggedOut.tsx:104 #: src/view/com/auth/LoggedOut.tsx:105 @@ -3399,21 +3543,21 @@ msgstr "ì‚¬ìš©ìž ê²€ìƒ‰í•˜ê¸°" msgid "Security Step Required" msgstr "보안 단계 í•„ìš”" -#: src/components/TagMenu/index.web.tsx:50 +#: src/components/TagMenu/index.web.tsx:66 msgid "See {truncatedTag} posts" -msgstr "" +msgstr "{truncatedTag} 게시물 보기" -#: src/components/TagMenu/index.web.tsx:67 +#: src/components/TagMenu/index.web.tsx:83 msgid "See {truncatedTag} posts by user" -msgstr "" +msgstr "ì´ ì‚¬ìš©ìžì˜ {truncatedTag} 게시물 보기" #: src/components/TagMenu/index.tsx:128 -msgid "See <0>{tag}</0> posts" -msgstr "" +msgid "See <0>{displayTag}</0> posts" +msgstr "<0>{displayTag}</0> 게시물 보기" -#: src/components/TagMenu/index.tsx:189 -msgid "See <0>{tag}</0> posts by this user" -msgstr "" +#: src/components/TagMenu/index.tsx:187 +msgid "See <0>{displayTag}</0> posts by this user" +msgstr "ì´ ì‚¬ìš©ìžì˜ <0>{displayTag}</0> 게시물 보기" #: src/view/screens/SavedFeeds.tsx:163 msgid "See this guide" @@ -3427,19 +3571,19 @@ msgstr "See what's next" msgid "Select {item}" msgstr "{item} ì„ íƒ" -#: src/view/com/modals/ServerInput.tsx:75 -#~ msgid "Select Bluesky Social" -#~ msgstr "Bluesky Social ì„ íƒ" - #: src/view/com/auth/login/Login.tsx:117 msgid "Select from an existing account" msgstr "기존 ê³„ì •ì—서 ì„ íƒ" +#: src/components/ReportDialog/SelectLabelerView.tsx:30 +msgid "Select moderation service" +msgstr "ê²€í† ì„œë¹„ìŠ¤ ì„ íƒí•˜ê¸°" + #: src/view/com/util/Selector.tsx:107 msgid "Select option {i} of {numItems}" msgstr "{numItems}ê°œ 중 {i}번째 ì˜µì…˜ì„ ì„ íƒí•©ë‹ˆë‹¤" -#: src/view/com/auth/create/Step1.tsx:103 +#: src/view/com/auth/create/Step1.tsx:96 #: src/view/com/auth/login/LoginForm.tsx:150 msgid "Select service" msgstr "서비스 ì„ íƒ" @@ -3448,15 +3592,19 @@ msgstr "서비스 ì„ íƒ" msgid "Select some accounts below to follow" msgstr "아래ì—서 íŒ”ë¡œìš°í• ê³„ì •ì„ ì„ íƒí•˜ì„¸ìš”" +#: src/components/ReportDialog/SubmitView.tsx:135 +msgid "Select the moderation service(s) to report to" +msgstr "ì‹ ê³ í• ê²€í† ì„œë¹„ìŠ¤ë¥¼ ì„ íƒí•©ë‹ˆë‹¤." + #: src/view/com/auth/server-input/index.tsx:82 msgid "Select the service that hosts your data." -msgstr "" +msgstr "ë°ì´í„°ë¥¼ í˜¸ìŠ¤íŒ…í• ì„œë¹„ìŠ¤ë¥¼ ì„ íƒí•˜ì„¸ìš”." #: src/screens/Onboarding/StepTopicalFeeds.tsx:96 msgid "Select topical feeds to follow from the list below" msgstr "아래 목ë¡ì—서 íŒ”ë¡œìš°í• í™”ì œ 피드를 ì„ íƒí•˜ì„¸ìš”" -#: src/screens/Onboarding/StepModeration/index.tsx:75 +#: src/screens/Onboarding/StepModeration/index.tsx:62 msgid "Select what you want to see (or not see), and we’ll handle the rest." msgstr "ë³´ê³ ì‹¶ê±°ë‚˜ ë³´ê³ ì‹¶ì§€ ì•Šì€ í•ëª©ì„ ì„ íƒí•˜ë©´ 나머지는 알아서 처리해 드립니다." @@ -3472,10 +3620,6 @@ msgstr "ì•±ì— í‘œì‹œë˜ëŠ” 기본 í…스트 언어를 ì„ íƒí•©ë‹ˆë‹¤." msgid "Select your interests from the options below" msgstr "아래 옵션ì—서 관심사를 ì„ íƒí•˜ì„¸ìš”" -#: src/view/com/auth/create/Step2.tsx:155 -#~ msgid "Select your phone's country" -#~ msgstr "ì „í™”ë²ˆí˜¸ êµê°€ ì„ íƒ" - #: src/view/screens/LanguageSettings.tsx:190 msgid "Select your preferred language for translations in your feed." msgstr "피드ì—서 번ì—ì„ ìœ„í•´ ì„ í˜¸í•˜ëŠ” 언어를 ì„ íƒí•©ë‹ˆë‹¤." @@ -3507,53 +3651,52 @@ msgstr "ì´ë©”ì¼ ë³´ë‚´ê¸°" msgid "Send feedback" msgstr "피드백 보내기" -#: src/view/com/modals/report/SendReportButton.tsx:45 -msgid "Send Report" +#: src/components/ReportDialog/SubmitView.tsx:214 +#: src/components/ReportDialog/SubmitView.tsx:218 +msgid "Send report" msgstr "ì‹ ê³ ë³´ë‚´ê¸°" +#: src/components/ReportDialog/SelectLabelerView.tsx:44 +msgid "Send report to {0}" +msgstr "{0} 님ì—게 ì‹ ê³ ë³´ë‚´ê¸°" + #: src/view/com/modals/DeleteAccount.tsx:133 msgid "Sends email with confirmation code for account deletion" msgstr "ê³„ì • ì‚ì œë¥¼ 위한 í™•ì¸ ì½”ë“œê°€ í¬í•¨ëœ ì´ë©”ì¼ì„ ì „ì†¡í•©ë‹ˆë‹¤" #: src/view/com/auth/server-input/index.tsx:110 msgid "Server address" -msgstr "" - -#: src/view/com/modals/ContentFilteringSettings.tsx:311 -msgid "Set {value} for {labelGroup} content moderation policy" -msgstr "{labelGroup} 콘í…ì¸ ê´€ë¦¬ ì •ì±…ì— ëŒ€í•´ {value}ì„(를) ì„¤ì •í•©ë‹ˆë‹¤" +msgstr "서버 주소" -#: src/view/com/modals/ContentFilteringSettings.tsx:160 -#: src/view/com/modals/ContentFilteringSettings.tsx:179 -msgctxt "action" -msgid "Set Age" -msgstr "ë‚˜ì´ ì„¤ì •" +#: src/screens/Moderation/index.tsx:307 +msgid "Set birthdate" +msgstr "ìƒë…„ì›”ì¼ ì„¤ì •" -#: src/view/screens/Settings/index.tsx:488 +#: src/view/screens/Settings/index.tsx:506 msgid "Set color theme to dark" msgstr "ìƒ‰ìƒ í…Œë§ˆë¥¼ ì–´ë‘움으로 ì„¤ì •í•©ë‹ˆë‹¤" -#: src/view/screens/Settings/index.tsx:481 +#: src/view/screens/Settings/index.tsx:499 msgid "Set color theme to light" msgstr "ìƒ‰ìƒ í…Œë§ˆë¥¼ ë°ìŒìœ¼ë¡œ ì„¤ì •í•©ë‹ˆë‹¤" -#: src/view/screens/Settings/index.tsx:475 +#: src/view/screens/Settings/index.tsx:493 msgid "Set color theme to system setting" msgstr "ìƒ‰ìƒ í…Œë§ˆë¥¼ 시스템 ì„¤ì •ì— ë§žì¶¥ë‹ˆë‹¤" -#: src/view/screens/Settings/index.tsx:514 +#: src/view/screens/Settings/index.tsx:532 msgid "Set dark theme to the dark theme" -msgstr "" +msgstr "ì–´ë‘ìš´ 테마를 ì™„ì „ížˆ 어둡게 ì„¤ì •í•©ë‹ˆë‹¤" -#: src/view/screens/Settings/index.tsx:507 +#: src/view/screens/Settings/index.tsx:525 msgid "Set dark theme to the dim theme" -msgstr "" +msgstr "ì–´ë‘ìš´ 테마를 ì‚´ì§ ë°ê²Œ ì„¤ì •í•©ë‹ˆë‹¤" #: src/view/com/auth/login/SetNewPasswordForm.tsx:104 msgid "Set new password" msgstr "새 비밀번호 ì„¤ì •" -#: src/view/com/auth/create/Step1.tsx:225 +#: src/view/com/auth/create/Step1.tsx:202 msgid "Set password" msgstr "비밀번호 ì„¤ì •" @@ -3573,13 +3716,9 @@ msgstr "피드ì—서 ëª¨ë“ ìž¬ê²Œì‹œë¥¼ ìˆ¨ê¸°ë ¤ë©´ ì´ ì„¤ì •ì„ \"아니요\ msgid "Set this setting to \"Yes\" to show replies in a threaded view. This is an experimental feature." msgstr "ìŠ¤ë ˆë“œ ë³´ê¸°ì— ë‹µê¸€ì„ í‘œì‹œí•˜ë ¤ë©´ ì´ ì„¤ì •ì„ \"예\"로 ì„¤ì •í•©ë‹ˆë‹¤. ì´ëŠ” 실험ì ì¸ ê¸°ëŠ¥ìž…ë‹ˆë‹¤." -#: src/view/screens/PreferencesHomeFeed.tsx:261 -#~ msgid "Set this setting to \"Yes\" to show samples of your saved feeds in your following feed. This is an experimental feature." -#~ msgstr "팔로우한 í”¼ë“œì— ì €ìž¥ëœ í”¼ë“œ ìƒ˜í”Œì„ í‘œì‹œí•˜ë ¤ë©´ ì´ ì„¤ì •ì„ \"예\"로 ì„¤ì •í•©ë‹ˆë‹¤. ì´ëŠ” 실험ì ì¸ ê¸°ëŠ¥ìž…ë‹ˆë‹¤." - #: src/view/screens/PreferencesFollowingFeed.tsx:261 msgid "Set this setting to \"Yes\" to show samples of your saved feeds in your Following feed. This is an experimental feature." -msgstr "" +msgstr "팔로우 중 í”¼ë“œì— ì €ìž¥ëœ í”¼ë“œ ìƒ˜í”Œì„ í‘œì‹œí•˜ë ¤ë©´ ì´ ì„¤ì •ì„ \"예\"로 ì„¤ì •í•©ë‹ˆë‹¤. ì´ëŠ” 실험ì ì¸ ê¸°ëŠ¥ìž…ë‹ˆë‹¤." #: src/screens/Onboarding/Layout.tsx:50 msgid "Set up your account" @@ -3597,13 +3736,13 @@ msgstr "비밀번호 ìž¬ì„¤ì •ì„ ìœ„í•œ ì´ë©”ì¼ì„ ì„¤ì •í•©ë‹ˆë‹¤" msgid "Sets hosting provider for password reset" msgstr "비밀번호 ìž¬ì„¤ì •ì„ ìœ„í•œ 호스팅 ì œê³µìžë¥¼ ì„¤ì •í•©ë‹ˆë‹¤" -#: src/view/com/auth/create/Step1.tsx:104 +#: src/view/com/auth/create/Step1.tsx:97 #: src/view/com/auth/login/LoginForm.tsx:151 msgid "Sets server for the Bluesky client" msgstr "Bluesky í´ë¼ì´ì–¸íŠ¸ë¥¼ 위한 서버를 ì„¤ì •í•©ë‹ˆë‹¤" -#: src/Navigation.tsx:135 -#: src/view/screens/Settings/index.tsx:294 +#: src/Navigation.tsx:139 +#: src/view/screens/Settings/index.tsx:312 #: src/view/shell/desktop/LeftNav.tsx:433 #: src/view/shell/Drawer.tsx:567 #: src/view/shell/Drawer.tsx:568 @@ -3614,26 +3753,39 @@ msgstr "ì„¤ì •" msgid "Sexual activity or erotic nudity." msgstr "성행위 ë˜ëŠ” ì„ ì •ì ì¸ ë…¸ì¶œ." +#: src/lib/moderation/useGlobalLabelStrings.ts:38 +msgid "Sexually Suggestive" +msgstr "외설ì " + #: src/view/com/lightbox/Lightbox.tsx:141 msgctxt "action" msgid "Share" msgstr "ê³µìœ " -#: src/view/com/profile/ProfileHeader.tsx:295 -#: src/view/com/util/forms/PostDropdownBtn.tsx:184 -#: src/view/screens/ProfileList.tsx:418 +#: src/view/com/profile/ProfileMenu.tsx:215 +#: src/view/com/profile/ProfileMenu.tsx:224 +#: src/view/com/util/forms/PostDropdownBtn.tsx:228 +#: src/view/com/util/forms/PostDropdownBtn.tsx:237 +#: src/view/com/util/post-ctrls/PostCtrls.tsx:218 +#: src/view/screens/ProfileList.tsx:388 msgid "Share" msgstr "ê³µìœ " -#: src/view/screens/ProfileFeed.tsx:305 +#: src/view/com/profile/ProfileMenu.tsx:373 +#: src/view/com/util/forms/PostDropdownBtn.tsx:347 +msgid "Share anyway" +msgstr "ë¬´ì‹œí•˜ê³ ê³µìœ " + +#: src/view/screens/ProfileFeed.tsx:361 +#: src/view/screens/ProfileFeed.tsx:363 msgid "Share feed" msgstr "피드 ê³µìœ " -#: src/screens/Onboarding/StepModeration/ModerationOption.tsx:43 -#: src/view/com/modals/ContentFilteringSettings.tsx:266 -#: src/view/com/util/moderation/ContentHider.tsx:107 -#: src/view/com/util/moderation/PostHider.tsx:108 -#: src/view/screens/Settings/index.tsx:344 +#: src/components/moderation/ContentHider.tsx:115 +#: src/components/moderation/GlobalModerationLabelPref.tsx:45 +#: src/components/moderation/PostHider.tsx:107 +#: src/screens/Onboarding/StepModeration/ModerationOption.tsx:54 +#: src/view/screens/Settings/index.tsx:362 msgid "Show" msgstr "표시" @@ -3641,21 +3793,31 @@ msgstr "표시" msgid "Show all replies" msgstr "ëª¨ë“ ë‹µê¸€ 표시" -#: src/view/com/util/moderation/ScreenHider.tsx:132 +#: src/components/moderation/ScreenHider.tsx:161 +#: src/components/moderation/ScreenHider.tsx:164 msgid "Show anyway" msgstr "ë¬´ì‹œí•˜ê³ í‘œì‹œ" +#: src/lib/moderation/useLabelBehaviorDescription.ts:27 +#: src/lib/moderation/useLabelBehaviorDescription.ts:63 +msgid "Show badge" +msgstr "ë°°ì§€ 표시" + +#: src/lib/moderation/useLabelBehaviorDescription.ts:61 +msgid "Show badge and filter from feeds" +msgstr "ë°°ì§€ 표시 ë° í”¼ë“œì—서 í•„í„°ë§" + #: src/view/com/modals/EmbedConsent.tsx:87 msgid "Show embeds from {0}" msgstr "{0} ìž„ë² ë“œ 표시" -#: src/view/com/profile/ProfileHeader.tsx:459 +#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:193 msgid "Show follows similar to {0}" msgstr "{0} 님과 비슷한 팔로우 표시" -#: src/view/com/post-thread/PostThreadItem.tsx:538 -#: src/view/com/post/Post.tsx:198 -#: src/view/com/posts/FeedItem.tsx:363 +#: src/view/com/post-thread/PostThreadItem.tsx:509 +#: src/view/com/post/Post.tsx:204 +#: src/view/com/posts/FeedItem.tsx:358 msgid "Show More" msgstr "ë” ë³´ê¸°" @@ -3669,15 +3831,15 @@ msgstr "ì¸ìš© 게시물 표시" #: src/screens/Onboarding/StepFollowingFeed.tsx:118 msgid "Show quote-posts in Following feed" -msgstr "팔로우 ì¤‘ì¸ í”¼ë“œì— ì¸ìš© 게시물 표시" +msgstr "팔로우 중 í”¼ë“œì— ì¸ìš© 게시물 표시" #: src/screens/Onboarding/StepFollowingFeed.tsx:134 msgid "Show quotes in Following" -msgstr "팔로우 ì¤‘ì¸ í”¼ë“œì— ì¸ìš© 표시" +msgstr "팔로우 중 í”¼ë“œì— ì¸ìš© 표시" #: src/screens/Onboarding/StepFollowingFeed.tsx:94 msgid "Show re-posts in Following feed" -msgstr "팔로우 ì¤‘ì¸ í”¼ë“œì— ìž¬ê²Œì‹œ 표시" +msgstr "팔로우 중 í”¼ë“œì— ìž¬ê²Œì‹œ 표시" #: src/view/screens/PreferencesFollowingFeed.tsx:119 msgid "Show Replies" @@ -3689,11 +3851,11 @@ msgstr "ë‚´ê°€ 팔로우하는 ì‚¬ëžŒë“¤ì˜ ë‹µê¸€ì„ ë‹¤ë¥¸ ëª¨ë“ ë‹µê¸€ë³´ë‹¤ #: src/screens/Onboarding/StepFollowingFeed.tsx:86 msgid "Show replies in Following" -msgstr "팔로우 ì¤‘ì¸ í”¼ë“œì— ë‹µê¸€ 표시" +msgstr "팔로우 중 í”¼ë“œì— ë‹µê¸€ 표시" #: src/screens/Onboarding/StepFollowingFeed.tsx:70 msgid "Show replies in Following feed" -msgstr "팔로우 ì¤‘ì¸ í”¼ë“œì— ë‹µê¸€ 표시" +msgstr "팔로우 중 í”¼ë“œì— ë‹µê¸€ 표시" #: src/view/screens/PreferencesFollowingFeed.tsx:70 msgid "Show replies with at least {value} {0}" @@ -3705,10 +3867,10 @@ msgstr "재게시 표시" #: src/screens/Onboarding/StepFollowingFeed.tsx:110 msgid "Show reposts in Following" -msgstr "팔로우 ì¤‘ì¸ í”¼ë“œì— ìž¬ê²Œì‹œ 표시" +msgstr "팔로우 중 í”¼ë“œì— ìž¬ê²Œì‹œ 표시" -#: src/view/com/util/moderation/ContentHider.tsx:67 -#: src/view/com/util/moderation/PostHider.tsx:61 +#: src/components/moderation/ContentHider.tsx:68 +#: src/components/moderation/PostHider.tsx:64 msgid "Show the content" msgstr "콘í…ì¸ í‘œì‹œ" @@ -3716,21 +3878,24 @@ msgstr "콘í…ì¸ í‘œì‹œ" msgid "Show users" msgstr "ì‚¬ìš©ìž í‘œì‹œ" -#: src/view/com/profile/ProfileHeader.tsx:462 -msgid "Shows a list of users similar to this user." -msgstr "ì´ ì‚¬ìš©ìžì™€ ìœ ì‚¬í•œ ì‚¬ìš©ìž ëª©ë¡ì„ 표시합니다" +#: src/lib/moderation/useLabelBehaviorDescription.ts:58 +msgid "Show warning" +msgstr "ê²½ê³ í‘œì‹œ" -#: src/view/com/post-thread/PostThreadFollowBtn.tsx:124 -#: src/view/com/profile/ProfileHeader.tsx:506 +#: src/lib/moderation/useLabelBehaviorDescription.ts:56 +msgid "Show warning and filter from feeds" +msgstr "ê²½ê³ í‘œì‹œ ë° í”¼ë“œì—서 í•„í„°ë§" + +#: src/view/com/post-thread/PostThreadFollowBtn.tsx:127 msgid "Shows posts from {0} in your feed" msgstr "í”¼ë“œì— {0} ë‹˜ì˜ ê²Œì‹œë¬¼ì„ í‘œì‹œí•©ë‹ˆë‹¤" #: src/view/com/auth/HomeLoggedOutCTA.tsx:70 #: src/view/com/auth/login/Login.tsx:98 #: src/view/com/auth/SplashScreen.tsx:79 -#: src/view/shell/bottom-bar/BottomBar.tsx:285 -#: src/view/shell/bottom-bar/BottomBar.tsx:286 +#: src/view/shell/bottom-bar/BottomBar.tsx:287 #: src/view/shell/bottom-bar/BottomBar.tsx:288 +#: src/view/shell/bottom-bar/BottomBar.tsx:290 #: src/view/shell/bottom-bar/BottomBarWeb.tsx:178 #: src/view/shell/bottom-bar/BottomBarWeb.tsx:179 #: src/view/shell/bottom-bar/BottomBarWeb.tsx:181 @@ -3760,14 +3925,14 @@ msgstr "로그ì¸" #: src/view/com/modals/SwitchAccount.tsx:64 #: src/view/com/modals/SwitchAccount.tsx:69 -#: src/view/screens/Settings/index.tsx:100 -#: src/view/screens/Settings/index.tsx:103 +#: src/view/screens/Settings/index.tsx:104 +#: src/view/screens/Settings/index.tsx:107 msgid "Sign out" msgstr "로그아웃" -#: src/view/shell/bottom-bar/BottomBar.tsx:275 -#: src/view/shell/bottom-bar/BottomBar.tsx:276 +#: src/view/shell/bottom-bar/BottomBar.tsx:277 #: src/view/shell/bottom-bar/BottomBar.tsx:278 +#: src/view/shell/bottom-bar/BottomBar.tsx:280 #: src/view/shell/bottom-bar/BottomBarWeb.tsx:168 #: src/view/shell/bottom-bar/BottomBarWeb.tsx:169 #: src/view/shell/bottom-bar/BottomBarWeb.tsx:171 @@ -3781,11 +3946,12 @@ msgstr "가입하기" msgid "Sign up or sign in to join the conversation" msgstr "가입 ë˜ëŠ” 로그ì¸í•˜ì—¬ ëŒ€í™”ì— ì°¸ì—¬í•˜ì„¸ìš”" -#: src/view/com/util/moderation/ScreenHider.tsx:76 +#: src/components/moderation/ScreenHider.tsx:97 +#: src/lib/moderation/useGlobalLabelStrings.ts:28 msgid "Sign-in Required" msgstr "ë¡œê·¸ì¸ í•„ìš”" -#: src/view/screens/Settings/index.tsx:355 +#: src/view/screens/Settings/index.tsx:373 msgid "Signed in as" msgstr "로그ì¸í•œ ê³„ì •" @@ -3807,23 +3973,21 @@ msgstr "건너뛰기" msgid "Skip this flow" msgstr "ì´ ë‹¨ê³„ 건너뛰기" -#: src/view/com/auth/create/Step2.tsx:82 -#~ msgid "SMS verification" -#~ msgstr "SMS ì¸ì¦" - #: src/screens/Onboarding/index.tsx:40 msgid "Software Dev" msgstr "소프트웨어 개발" -#: src/view/com/modals/ProfilePreview.tsx:62 -#~ msgid "Something went wrong and we're not sure what." -#~ msgstr "ë¬¸ì œê°€ ë°œìƒí–ˆì§€ë§Œ ì›ì¸ì„ 알 수 없습니다." +#: src/components/ReportDialog/index.tsx:50 +#: src/screens/Moderation/index.tsx:116 +#: src/screens/Profile/Sections/Labels.tsx:88 +msgid "Something went wrong, please try again." +msgstr "ë”ê°€ 잘못ë˜ì—ˆìŠµë‹ˆë‹¤. 다시 시ë„í•´ 주세요." -#: src/view/com/modals/Waitlist.tsx:51 -msgid "Something went wrong. Check your email and try again." -msgstr "ë¬¸ì œê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤. ì´ë©”ì¼ì„ 확ì¸í•œ 후 다시 시ë„하세요." +#: src/components/Lists.tsx:202 +msgid "Something went wrong!" +msgstr "ë”ê°€ 잘못ë˜ì—ˆìŠµë‹ˆë‹¤!" -#: src/App.native.tsx:63 +#: src/App.native.tsx:71 msgid "Sorry! Your session expired. Please log in again." msgstr "죄송합니다. ì„¸ì…˜ì´ ë§Œë£Œë˜ì—ˆìŠµë‹ˆë‹¤. 다시 로그ì¸í•´ 주세요." @@ -3835,6 +3999,18 @@ msgstr "답글 ì •ë ¬" msgid "Sort replies to the same post by:" msgstr "ë™ì¼í•œ ê²Œì‹œë¬¼ì— ëŒ€í•œ ë‹µê¸€ì„ ì •ë ¬í•˜ëŠ” 기준입니다." +#: src/components/moderation/LabelsOnMeDialog.tsx:147 +msgid "Source:" +msgstr "출처:" + +#: src/lib/moderation/useReportOptions.ts:65 +msgid "Spam" +msgstr "스팸" + +#: src/lib/moderation/useReportOptions.ts:53 +msgid "Spam; excessive mentions or replies" +msgstr "스팸, ê³¼ë„한 멘션 ë˜ëŠ” 답글" + #: src/screens/Onboarding/index.tsx:30 msgid "Sports" msgstr "스í¬ì¸ " @@ -3843,11 +4019,7 @@ msgstr "스í¬ì¸ " msgid "Square" msgstr "ì •ì‚¬ê°í˜•" -#: src/view/com/modals/ServerInput.tsx:62 -#~ msgid "Staging" -#~ msgstr "스테ì´ì§•" - -#: src/view/screens/Settings/index.tsx:871 +#: src/view/screens/Settings/index.tsx:899 msgid "Status page" msgstr "ìƒíƒœ 페ì´ì§€" @@ -3855,29 +4027,42 @@ msgstr "ìƒíƒœ 페ì´ì§€" msgid "Step {0} of {numSteps}" msgstr "{numSteps}단계 중 {0}단계" -#: src/view/screens/Settings/index.tsx:274 +#: src/view/screens/Settings/index.tsx:288 msgid "Storage cleared, you need to restart the app now." msgstr "ìŠ¤í† ë¦¬ì§€ê°€ 지워졌으며 지금 ì•±ì„ ë‹¤ì‹œ 시작해야 합니다." -#: src/Navigation.tsx:202 -#: src/view/screens/Settings/index.tsx:807 +#: src/Navigation.tsx:211 +#: src/view/screens/Settings/index.tsx:825 msgid "Storybook" msgstr "ìŠ¤í† ë¦¬ë¶" -#: src/view/com/modals/AppealLabel.tsx:101 +#: src/components/moderation/LabelsOnMeDialog.tsx:256 +#: src/components/moderation/LabelsOnMeDialog.tsx:257 msgid "Submit" msgstr "확ì¸" -#: src/view/screens/ProfileList.tsx:608 +#: src/view/screens/ProfileList.tsx:590 msgid "Subscribe" msgstr "구ë…" +#: src/screens/Profile/Sections/Labels.tsx:199 +msgid "Subscribe to @{0} to use these labels:" +msgstr "ì´ ë¼ë²¨ì„ ì‚¬ìš©í•˜ë ¤ë©´ @{0} ë‹˜ì„ êµ¬ë…하세요:" + +#: src/screens/Profile/Header/ProfileHeaderLabeler.tsx:222 +msgid "Subscribe to Labeler" +msgstr "ë¼ë²¨ëŸ¬ 구ë…" + #: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:173 -#: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:307 +#: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:308 msgid "Subscribe to the {0} feed" msgstr "{0} 피드 구ë…하기" -#: src/view/screens/ProfileList.tsx:604 +#: src/screens/Profile/Header/ProfileHeaderLabeler.tsx:185 +msgid "Subscribe to this labeler" +msgstr "ì´ ë¼ë²¨ëŸ¬ 구ë…하기" + +#: src/view/screens/ProfileList.tsx:586 msgid "Subscribe to this list" msgstr "ì´ ë¦¬ìŠ¤íŠ¸ 구ë…하기" @@ -3893,45 +4078,41 @@ msgstr "나를 위한 추천" msgid "Suggestive" msgstr "외설ì " -#: src/Navigation.tsx:212 +#: src/Navigation.tsx:226 #: src/view/screens/Support.tsx:30 #: src/view/screens/Support.tsx:33 msgid "Support" msgstr "ì§€ì›" -#: src/view/com/modals/ProfilePreview.tsx:110 -#~ msgid "Swipe up to see more" -#~ msgstr "위로 스와ì´í”„하여 ë” ë³´ê¸°" - #: src/view/com/modals/SwitchAccount.tsx:117 msgid "Switch Account" msgstr "ê³„ì • ì „í™˜" #: src/view/com/modals/SwitchAccount.tsx:97 -#: src/view/screens/Settings/index.tsx:130 +#: src/view/screens/Settings/index.tsx:134 msgid "Switch to {0}" msgstr "{0}(으)로 ì „í™˜" #: src/view/com/modals/SwitchAccount.tsx:98 -#: src/view/screens/Settings/index.tsx:131 +#: src/view/screens/Settings/index.tsx:135 msgid "Switches the account you are logged in to" msgstr "로그ì¸í•œ ê³„ì •ì„ ì „í™˜í•©ë‹ˆë‹¤" -#: src/view/screens/Settings/index.tsx:472 +#: src/view/screens/Settings/index.tsx:490 msgid "System" msgstr "시스템" -#: src/view/screens/Settings/index.tsx:795 +#: src/view/screens/Settings/index.tsx:813 msgid "System log" msgstr "시스템 로그" -#: src/components/dialogs/MutedWords.tsx:288 +#: src/components/dialogs/MutedWords.tsx:324 msgid "tag" -msgstr "" +msgstr "태그" -#: src/components/TagMenu/index.tsx:74 -msgid "Tag menu: {tag}" -msgstr "" +#: src/components/TagMenu/index.tsx:78 +msgid "Tag menu: {displayTag}" +msgstr "태그 메뉴: {displayTag}" #: src/view/com/modals/crop-image/CropImage.web.tsx:112 msgid "Tall" @@ -3949,29 +4130,43 @@ msgstr "ê¸°ìˆ " msgid "Terms" msgstr "ì´ìš©ì•½ê´€" -#: src/Navigation.tsx:222 -#: src/view/screens/Settings/index.tsx:885 +#: src/Navigation.tsx:236 +#: src/view/screens/Settings/index.tsx:913 #: src/view/screens/TermsOfService.tsx:29 #: src/view/shell/Drawer.tsx:256 msgid "Terms of Service" msgstr "서비스 ì´ìš©ì•½ê´€" -#: src/components/dialogs/MutedWords.tsx:288 +#: src/lib/moderation/useReportOptions.ts:58 +#: src/lib/moderation/useReportOptions.ts:79 +#: src/lib/moderation/useReportOptions.ts:87 +msgid "Terms used violate community standards" +msgstr "커뮤니티 ê¸°ì¤€ì„ ìœ„ë°˜í•˜ëŠ” 용어 사용" + +#: src/components/dialogs/MutedWords.tsx:324 msgid "text" -msgstr "" +msgstr "글" -#: src/view/com/modals/AppealLabel.tsx:70 -#: src/view/com/modals/report/InputIssueDetails.tsx:51 +#: src/components/moderation/LabelsOnMeDialog.tsx:220 msgid "Text input field" msgstr "í…스트 ìž…ë ¥ 필드" +#: src/components/ReportDialog/SubmitView.tsx:78 +msgid "Thank you. Your report has been sent." +msgstr "ê°ì‚¬í•©ë‹ˆë‹¤. ì‹ ê³ ë¥¼ ì „ì†¡í–ˆìŠµë‹ˆë‹¤." + #: src/view/com/auth/create/CreateAccount.tsx:94 msgid "That handle is already taken." -msgstr "" +msgstr "ì´ í•¸ë“¤ì€ ì´ë¯¸ 사용 중입니다." -#: src/view/com/profile/ProfileHeader.tsx:263 +#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:274 +#: src/view/com/profile/ProfileMenu.tsx:349 msgid "The account will be able to interact with you after unblocking." -msgstr "ì°¨ë‹¨ì„ í•´ì œí•˜ë©´ 해당 ê³„ì •ì´ ë‚˜ì™€ ìƒí˜¸ìž‘ìš©í• ìˆ˜ 있게 ë©ë‹ˆë‹¤." +msgstr "ì°¨ë‹¨ì„ í•´ì œí•˜ë©´ ì´ ê³„ì •ì´ ë‚˜ì™€ ìƒí˜¸ìž‘ìš©í• ìˆ˜ 있게 ë©ë‹ˆë‹¤." + +#: src/components/moderation/ModerationDetailsDialog.tsx:128 +msgid "the author" +msgstr "작성ìž" #: src/view/screens/CommunityGuidelines.tsx:36 msgid "The Community Guidelines have been moved to <0/>" @@ -3981,11 +4176,19 @@ msgstr "커뮤니티 ê°€ì´ë“œë¼ì¸ì„ <0/>(으)로 ì´ë™í–ˆìŠµë‹ˆë‹¤" msgid "The Copyright Policy has been moved to <0/>" msgstr "ì €ìž‘ê¶Œ ì •ì±…ì„ <0/>(으)로 ì´ë™í–ˆìŠµë‹ˆë‹¤" +#: src/components/moderation/LabelsOnMeDialog.tsx:49 +msgid "The following labels were applied to your account." +msgstr "ë‚´ ê³„ì •ì— ë‹¤ìŒ ë¼ë²¨ì´ ì ìš©ë˜ì—ˆìŠµë‹ˆë‹¤." + +#: src/components/moderation/LabelsOnMeDialog.tsx:50 +msgid "The following labels were applied to your content." +msgstr "ë‚´ 콘í…ì¸ ì— ë‹¤ìŒ ë¼ë²¨ì´ ì ìš©ë˜ì—ˆìŠµë‹ˆë‹¤." + #: src/screens/Onboarding/Layout.tsx:60 msgid "The following steps will help customize your Bluesky experience." msgstr "ë‹¤ìŒ ë‹¨ê³„ëŠ” Bluesky í™˜ê²½ì„ ë§žì¶¤ ì„¤ì •í•˜ëŠ” ë° ë„ì›€ì´ ë©ë‹ˆë‹¤." -#: src/view/com/post-thread/PostThread.tsx:517 +#: src/view/com/post-thread/PostThread.tsx:518 msgid "The post may have been deleted." msgstr "ê²Œì‹œë¬¼ì´ ì‚ì œë˜ì—ˆì„ 수 있습니다." @@ -4005,20 +4208,21 @@ msgstr "서비스 ì´ìš©ì•½ê´€ì„ 다ìŒìœ¼ë¡œ ì´ë™í–ˆìŠµë‹ˆë‹¤:" msgid "There are many feeds to try:" msgstr "시ë„í•´ ë³¼ 만한 피드:" -#: src/view/screens/ProfileFeed.tsx:550 +#: src/screens/Profile/Header/ProfileHeaderLabeler.tsx:113 +#: src/view/screens/ProfileFeed.tsx:543 msgid "There was an an issue contacting the server, please check your internet connection and try again." msgstr "ì„œë²„ì— ì—°ê²°í•˜ëŠ” ë™ì•ˆ ë¬¸ì œê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤. ì¸í„°ë„· ì—°ê²°ì„ í™•ì¸í•œ 후 다시 시ë„하세요." -#: src/view/com/posts/FeedErrorMessage.tsx:139 +#: src/view/com/posts/FeedErrorMessage.tsx:138 msgid "There was an an issue removing this feed. Please check your internet connection and try again." msgstr "ì´ í”¼ë“œë¥¼ ì‚ì œí•˜ëŠ” ë™ì•ˆ ë¬¸ì œê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤. ì¸í„°ë„· ì—°ê²°ì„ í™•ì¸í•œ 후 다시 시ë„하세요." -#: src/view/screens/ProfileFeed.tsx:210 +#: src/view/screens/ProfileFeed.tsx:217 msgid "There was an an issue updating your feeds, please check your internet connection and try again." msgstr "피드를 ì—…ë°ì´íŠ¸í•˜ëŠ” ë™ì•ˆ ë¬¸ì œê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤. ì¸í„°ë„· ì—°ê²°ì„ í™•ì¸í•œ 후 다시 시ë„하세요." -#: src/view/screens/ProfileFeed.tsx:237 -#: src/view/screens/ProfileList.tsx:267 +#: src/view/screens/ProfileFeed.tsx:244 +#: src/view/screens/ProfileList.tsx:275 #: src/view/screens/SavedFeeds.tsx:209 #: src/view/screens/SavedFeeds.tsx:231 #: src/view/screens/SavedFeeds.tsx:252 @@ -4027,9 +4231,8 @@ msgstr "ì„œë²„ì— ì—°ê²°í•˜ëŠ” ë™ì•ˆ ë¬¸ì œê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤" #: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:57 #: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:66 -#: src/view/com/feeds/FeedSourceCard.tsx:115 -#: src/view/com/feeds/FeedSourceCard.tsx:129 -#: src/view/com/feeds/FeedSourceCard.tsx:183 +#: src/view/com/feeds/FeedSourceCard.tsx:110 +#: src/view/com/feeds/FeedSourceCard.tsx:123 msgid "There was an issue contacting your server" msgstr "ì„œë²„ì— ì—°ê²°í•˜ëŠ” ë™ì•ˆ ë¬¸ì œê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤" @@ -4037,7 +4240,7 @@ msgstr "ì„œë²„ì— ì—°ê²°í•˜ëŠ” ë™ì•ˆ ë¬¸ì œê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤" msgid "There was an issue fetching notifications. Tap here to try again." msgstr "ì•Œë¦¼ì„ ê°€ì ¸ì˜¤ëŠ” ë™ì•ˆ ë¬¸ì œê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤. ì´ê³³ì„ íƒí•˜ì—¬ 다시 시ë„하세요." -#: src/view/com/posts/Feed.tsx:263 +#: src/view/com/posts/Feed.tsx:279 msgid "There was an issue fetching posts. Tap here to try again." msgstr "ê²Œì‹œë¬¼ì„ ê°€ì ¸ì˜¤ëŠ” ë™ì•ˆ ë¬¸ì œê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤. ì´ê³³ì„ íƒí•˜ì—¬ 다시 시ë„하세요." @@ -4050,34 +4253,40 @@ msgstr "리스트를 ê°€ì ¸ì˜¤ëŠ” ë™ì•ˆ ë¬¸ì œê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤. ì´ê³³ì„ msgid "There was an issue fetching your lists. Tap here to try again." msgstr "리스트를 ê°€ì ¸ì˜¤ëŠ” ë™ì•ˆ ë¬¸ì œê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤. ì´ê³³ì„ íƒí•˜ì—¬ 다시 시ë„하세요." -#: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:63 -#: src/view/com/modals/ContentFilteringSettings.tsx:126 +#: src/components/ReportDialog/SubmitView.tsx:83 +msgid "There was an issue sending your report. Please check your internet connection." +msgstr "ì‹ ê³ ë¥¼ ì „ì†¡í•˜ëŠ” ë™ì•ˆ ë¬¸ì œê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤. ì¸í„°ë„· ì—°ê²°ì„ í™•ì¸í•´ 주세요." + +#: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:65 msgid "There was an issue syncing your preferences with the server" msgstr "ì„¤ì •ì„ ì„œë²„ì™€ ë™ê¸°í™”하는 ë™ì•ˆ ë¬¸ì œê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤" -#: src/view/screens/AppPasswords.tsx:66 +#: src/view/screens/AppPasswords.tsx:68 msgid "There was an issue with fetching your app passwords" msgstr "앱 비밀번호를 ê°€ì ¸ì˜¤ëŠ” ë™ì•ˆ ë¬¸ì œê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤" -#: src/view/com/post-thread/PostThreadFollowBtn.tsx:93 -#: src/view/com/post-thread/PostThreadFollowBtn.tsx:105 -#: src/view/com/profile/ProfileHeader.tsx:157 -#: src/view/com/profile/ProfileHeader.tsx:178 -#: src/view/com/profile/ProfileHeader.tsx:217 -#: src/view/com/profile/ProfileHeader.tsx:230 -#: src/view/com/profile/ProfileHeader.tsx:250 -#: src/view/com/profile/ProfileHeader.tsx:272 +#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:98 +#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:120 +#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:134 +#: src/view/com/post-thread/PostThreadFollowBtn.tsx:96 +#: src/view/com/post-thread/PostThreadFollowBtn.tsx:108 +#: src/view/com/profile/ProfileMenu.tsx:106 +#: src/view/com/profile/ProfileMenu.tsx:117 +#: src/view/com/profile/ProfileMenu.tsx:132 +#: src/view/com/profile/ProfileMenu.tsx:143 +#: src/view/com/profile/ProfileMenu.tsx:157 +#: src/view/com/profile/ProfileMenu.tsx:170 msgid "There was an issue! {0}" msgstr "ë¬¸ì œê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤! {0}" #: src/view/screens/ProfileList.tsx:288 -#: src/view/screens/ProfileList.tsx:307 -#: src/view/screens/ProfileList.tsx:329 -#: src/view/screens/ProfileList.tsx:348 +#: src/view/screens/ProfileList.tsx:302 +#: src/view/screens/ProfileList.tsx:316 +#: src/view/screens/ProfileList.tsx:330 msgid "There was an issue. Please check your internet connection and try again." msgstr "ë¬¸ì œê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤. ì¸í„°ë„· ì—°ê²°ì„ í™•ì¸í•œ 후 다시 시ë„하세요." -#: src/view/com/util/ErrorBoundary.tsx:36 +#: src/view/com/util/ErrorBoundary.tsx:51 msgid "There was an unexpected issue in the application. Please let us know if this happened to you!" msgstr "ì• í”Œë¦¬ì¼€ì´ì…˜ì— 예기치 ì•Šì€ ë¬¸ì œê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤. ì´ëŸ° ì¼ì´ ë°œìƒí•˜ë©´ ì €í¬ì—게 ì•Œë ¤ì£¼ì„¸ìš”!" @@ -4085,27 +4294,36 @@ msgstr "ì• í”Œë¦¬ì¼€ì´ì…˜ì— 예기치 ì•Šì€ ë¬¸ì œê°€ ë°œìƒí–ˆìŠµë‹ˆë‹¤. ì´ msgid "There's been a rush of new users to Bluesky! We'll activate your account as soon as we can." msgstr "Blueskyì— ì‹ ê·œ 사용ìžê°€ ëª°ë¦¬ê³ ìžˆìŠµë‹ˆë‹¤! 최대한 빨리 ê³„ì •ì„ í™œì„±í™”í•´ ë“œë¦¬ê² ìŠµë‹ˆë‹¤." -#: src/view/com/auth/create/Step2.tsx:55 -#~ msgid "There's something wrong with this number. Please choose your country and enter your full phone number!" -#~ msgstr "ìž˜ëª»ëœ ë²ˆí˜¸ìž…ë‹ˆë‹¤. êµê°€ë¥¼ ì„ íƒí•˜ê³ ì „ì²´ ì „í™”ë²ˆí˜¸ë¥¼ ìž…ë ¥í•˜ì„¸ìš”." - #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:138 msgid "These are popular accounts you might like:" msgstr "ë‚´ê°€ ì¢‹ì•„í• ë§Œí•œ ì¸ê¸° ê³„ì •ìž…ë‹ˆë‹¤:" -#: src/view/com/util/moderation/ScreenHider.tsx:88 +#: src/components/moderation/ScreenHider.tsx:116 msgid "This {screenDescription} has been flagged:" -msgstr "ì´ {screenDescription}ì— í”Œëž˜ê·¸ê°€ ì§€ì •ë˜ì—ˆìŠµë‹ˆë‹¤:" +msgstr "ì´ {screenDescription}ì— ë‹¤ìŒ í”Œëž˜ê·¸ê°€ ì§€ì •ë˜ì—ˆìŠµë‹ˆë‹¤:" -#: src/view/com/util/moderation/ScreenHider.tsx:83 +#: src/components/moderation/ScreenHider.tsx:111 msgid "This account has requested that users sign in to view their profile." msgstr "ì´ ê³„ì •ì˜ í”„ë¡œí•„ì„ ë³´ë ¤ë©´ 로그ì¸í•´ì•¼ 합니다." +#: src/components/moderation/LabelsOnMeDialog.tsx:205 +msgid "This appeal will be sent to <0>{0}</0>." +msgstr "ì´ ì´ì˜ì‹ ì²ì€ <0>{0}</0>ì—게 보내집니다." + +#: src/lib/moderation/useGlobalLabelStrings.ts:19 +msgid "This content has been hidden by the moderators." +msgstr "ì´ ì½˜í…ì¸ ëŠ” 관리ìžì— ì˜í•´ 숨겨졌습니다." + +#: src/lib/moderation/useGlobalLabelStrings.ts:24 +msgid "This content has received a general warning from moderators." +msgstr "ì´ ì½˜í…ì¸ ëŠ” 관리ìžë¡œë¶€í„° ì¼ë°˜ ê²½ê³ ë¥¼ 받았습니다." + #: src/view/com/modals/EmbedConsent.tsx:68 msgid "This content is hosted by {0}. Do you want to enable external media?" msgstr "ì´ ì½˜í…ì¸ ëŠ” {0}ì—서 호스팅ë©ë‹ˆë‹¤. 외부 미디어를 ì‚¬ìš©í•˜ì‹œê² ìŠµë‹ˆê¹Œ?" -#: src/view/com/modals/ModerationDetails.tsx:67 +#: src/components/moderation/ModerationDetailsDialog.tsx:78 +#: src/lib/moderation/useModerationCauseDescription.ts:77 msgid "This content is not available because one of the users involved has blocked the other." msgstr "ê´€ë ¨ ì‚¬ìš©ìž ì¤‘ 한 ëª…ì´ ë‹¤ë¥¸ 사용ìžë¥¼ 차단했기 ë•Œë¬¸ì— ì´ ì½˜í…ì¸ ë¥¼ ì‚¬ìš©í• ìˆ˜ 없습니다." @@ -4115,15 +4333,15 @@ msgstr "ì´ ì½˜í…ì¸ ëŠ” Bluesky ê³„ì •ì´ ì—†ìœ¼ë©´ ë³¼ 수 없습니다." #: src/view/screens/Settings/ExportCarDialog.tsx:75 msgid "This feature is in beta. You can read more about repository exports in <0>this blogpost.</0>" -msgstr "" +msgstr "ì´ ê¸°ëŠ¥ì€ ë² íƒ€ ë²„ì „ìž…ë‹ˆë‹¤. ì €ìž¥ì†Œ ë‚´ë³´ë‚´ê¸°ì— ëŒ€í•œ ìžì„¸í•œ ë‚´ìš©ì€ <0>ì´ ë¸”ë¡œê·¸ 글</0>ì—서 확ì¸í• 수 있습니다." #: src/view/com/posts/FeedErrorMessage.tsx:114 msgid "This feed is currently receiving high traffic and is temporarily unavailable. Please try again later." msgstr "ì´ í”¼ë“œëŠ” 현재 íŠ¸ëž˜í”½ì´ ë§Žì•„ ì¼ì‹œì 으로 ì‚¬ìš©í• ìˆ˜ 없습니다. ë‚˜ì¤‘ì— ë‹¤ì‹œ 시ë„í•´ 주세요." -#: src/view/screens/Profile.tsx:420 +#: src/screens/Profile/Sections/Feed.tsx:50 #: src/view/screens/ProfileFeed.tsx:476 -#: src/view/screens/ProfileList.tsx:661 +#: src/view/screens/ProfileList.tsx:675 msgid "This feed is empty!" msgstr "ì´ í”¼ë“œëŠ” 비어 있습니다." @@ -4131,7 +4349,7 @@ msgstr "ì´ í”¼ë“œëŠ” 비어 있습니다." msgid "This feed is empty! You may need to follow more users or tune your language settings." msgstr "ì´ í”¼ë“œëŠ” 비어 있습니다. ë” ë§Žì€ ì‚¬ìš©ìžë¥¼ 팔로우하거나 언어 ì„¤ì •ì„ ì¡°ì •í•´ 보세요." -#: src/view/com/modals/BirthDateSettings.tsx:61 +#: src/components/dialogs/BirthDateSettings.tsx:89 msgid "This information is not shared with other users." msgstr "ì´ ì •ë³´ëŠ” 다른 사용ìžì™€ ê³µìœ ë˜ì§€ 않습니다." @@ -4139,14 +4357,26 @@ msgstr "ì´ ì •ë³´ëŠ” 다른 사용ìžì™€ ê³µìœ ë˜ì§€ 않습니다." msgid "This is important in case you ever need to change your email or reset your password." msgstr "ì´ëŠ” ì´ë©”ì¼ì„ 변경하거나 비밀번호를 ìž¬ì„¤ì •í•´ì•¼ í• ë•Œ 중요한 ì •ë³´ìž…ë‹ˆë‹¤." +#: src/components/moderation/ModerationDetailsDialog.tsx:125 +msgid "This label was applied by {0}." +msgstr "ì´ ë¼ë²¨ì€ {0}ì´(ê°€) ì 용했습니다." + +#: src/screens/Profile/Sections/Labels.tsx:186 +msgid "This labeler hasn't declared what labels it publishes, and may not be active." +msgstr "ì´ ë¼ë²¨ëŸ¬ëŠ” ë¼ë²¨ì„ 게시하지 않았으며 활성화ë˜ì–´ 있지 ì•Šì„ ìˆ˜ 있습니다." + #: src/view/com/modals/LinkWarning.tsx:58 msgid "This link is taking you to the following website:" msgstr "ì´ ë§í¬ë¥¼ í´ë¦í•˜ë©´ ë‹¤ìŒ ì›¹ì‚¬ì´íŠ¸ë¡œ ì´ë™í•©ë‹ˆë‹¤:" -#: src/view/screens/ProfileList.tsx:834 +#: src/view/screens/ProfileList.tsx:853 msgid "This list is empty!" msgstr "ì´ ë¦¬ìŠ¤íŠ¸ëŠ” 비어 있습니다." +#: src/screens/Profile/ErrorState.tsx:40 +msgid "This moderation service is unavailable. See below for more details. If this issue persists, contact us." +msgstr "ì´ ê²€í† ì„œë¹„ìŠ¤ëŠ” ì‚¬ìš©í• ìˆ˜ 없습니다. ìžì„¸í•œ ë‚´ìš©ì€ ì•„ëž˜ë¥¼ 참조하세요. ì´ ë¬¸ì œê°€ ì§€ì†ë˜ë©´ 문ì˜í•´ 주세요." + #: src/view/com/modals/AddAppPasswords.tsx:106 msgid "This name is already in use" msgstr "ì´ ì´ë¦„ì€ ì´ë¯¸ 사용 중입니다" @@ -4155,36 +4385,45 @@ msgstr "ì´ ì´ë¦„ì€ ì´ë¯¸ 사용 중입니다" msgid "This post has been deleted." msgstr "ì´ ê²Œì‹œë¬¼ì€ ì‚ì œë˜ì—ˆìŠµë‹ˆë‹¤." -#: src/view/com/modals/ModerationDetails.tsx:62 +#: src/view/com/util/forms/PostDropdownBtn.tsx:344 +msgid "This post is only visible to logged-in users. It won't be visible to people who aren't logged in." +msgstr "ì´ ê²Œì‹œë¬¼ì€ ë¡œê·¸ì¸í•œ 사용ìžì—게만 표시ë©ë‹ˆë‹¤. 로그ì¸í•˜ì§€ ì•Šì€ ì‚¬ìš©ìžì—게는 표시ë˜ì§€ 않습니다." + +#: src/view/com/util/forms/PostDropdownBtn.tsx:326 +msgid "This post will be hidden from feeds." +msgstr "ì´ ê²Œì‹œë¬¼ì„ í”¼ë“œì—서 숨ê¹ë‹ˆë‹¤." + +#: src/view/com/profile/ProfileMenu.tsx:370 +msgid "This profile is only visible to logged-in users. It won't be visible to people who aren't logged in." +msgstr "ì´ í”„ë¡œí•„ì€ ë¡œê·¸ì¸í•œ 사용ìžì—게만 표시ë©ë‹ˆë‹¤. 로그ì¸í•˜ì§€ ì•Šì€ ì‚¬ìš©ìžì—게는 표시ë˜ì§€ 않습니다." + +#: src/components/moderation/ModerationDetailsDialog.tsx:73 +#: src/lib/moderation/useModerationCauseDescription.ts:68 msgid "This user has blocked you. You cannot view their content." msgstr "ì´ ì‚¬ìš©ìžëŠ” 나를 차단했습니다. ì´ ì‚¬ìš©ìžì˜ 콘í…ì¸ ë¥¼ ë³¼ 수 없습니다." -#: src/view/com/modals/ModerationDetails.tsx:42 -msgid "This user is included in the <0/> list which you have blocked." -msgstr "ì´ ì‚¬ìš©ìžëŠ” 차단한 <0/> ë¦¬ìŠ¤íŠ¸ì— í¬í•¨ë˜ì–´ 있습니다." +#: src/lib/moderation/useGlobalLabelStrings.ts:30 +msgid "This user has requested that their content only be shown to signed-in users." +msgstr "ì´ ì‚¬ìš©ìžëŠ” ìžì‹ ì˜ ì½˜í…ì¸ ê°€ 로그ì¸í•œ 사용ìžì—게만 표시ë˜ë„ë¡ ìš”ì²í–ˆìŠµë‹ˆë‹¤." -#: src/view/com/modals/ModerationDetails.tsx:74 -msgid "This user is included in the <0/> list which you have muted." -msgstr "" +#: src/components/moderation/ModerationDetailsDialog.tsx:56 +msgid "This user is included in the <0>{0}</0> list which you have blocked." +msgstr "ì´ ì‚¬ìš©ìžëŠ” ë‚´ê°€ 차단한 <0>{0}</0> ë¦¬ìŠ¤íŠ¸ì— í¬í•¨ë˜ì–´ 있습니다." -#: src/view/com/modals/ModerationDetails.tsx:74 -#~ msgid "This user is included the <0/> list which you have muted." -#~ msgstr "ì´ ì‚¬ìš©ìžëŠ” 뮤트한 <0/> ë¦¬ìŠ¤íŠ¸ì— í¬í•¨ë˜ì–´ 있습니다." +#: src/components/moderation/ModerationDetailsDialog.tsx:85 +msgid "This user is included in the <0>{0}</0> list which you have muted." +msgstr "ì´ ì‚¬ìš©ìžëŠ” ë‚´ê°€ 뮤트한 <0>{0}</0> ë¦¬ìŠ¤íŠ¸ì— í¬í•¨ë˜ì–´ 있습니다." #: src/view/com/modals/SelfLabel.tsx:137 msgid "This warning is only available for posts with media attached." msgstr "ì´ ê²½ê³ ëŠ” 미디어가 ì²¨ë¶€ëœ ê²Œì‹œë¬¼ì—ë§Œ ì‚¬ìš©í• ìˆ˜ 있습니다." -#: src/components/dialogs/MutedWords.tsx:236 +#: src/components/dialogs/MutedWords.tsx:284 msgid "This will delete {0} from your muted words. You can always add it back later." -msgstr "" - -#: src/view/com/util/forms/PostDropdownBtn.tsx:237 -msgid "This will hide this post from your feeds." -msgstr "피드ì—서 ì´ ê²Œì‹œë¬¼ì„ ìˆ¨ê¹ë‹ˆë‹¤." +msgstr "뮤트한 단어ì—서 {0}ì´(ê°€) ì‚ì œë©ë‹ˆë‹¤. ë‚˜ì¤‘ì— ì–¸ì œë“ ì§€ 다시 ì¶”ê°€í• ìˆ˜ 있습니다." #: src/view/screens/PreferencesThreads.tsx:53 -#: src/view/screens/Settings/index.tsx:565 +#: src/view/screens/Settings/index.tsx:583 msgid "Thread Preferences" msgstr "ìŠ¤ë ˆë“œ ì„¤ì •" @@ -4192,25 +4431,30 @@ msgstr "ìŠ¤ë ˆë“œ ì„¤ì •" msgid "Threaded Mode" msgstr "ìŠ¤ë ˆë“œ 모드" -#: src/Navigation.tsx:255 +#: src/Navigation.tsx:269 msgid "Threads Preferences" msgstr "ìŠ¤ë ˆë“œ ì„¤ì •" -#: src/components/dialogs/MutedWords.tsx:95 +#: src/components/dialogs/MutedWords.tsx:113 msgid "Toggle between muted word options." -msgstr "" +msgstr "뮤트한 단어 옵션 사ì´ë¥¼ ì „í™˜í•©ë‹ˆë‹¤." #: src/view/com/util/forms/DropdownButton.tsx:246 msgid "Toggle dropdown" msgstr "드ë¡ë‹¤ìš´ 열기 ë° ë‹«ê¸°" +#: src/screens/Moderation/index.tsx:338 +msgid "Toggle to enable or disable adult content" +msgstr "ì„±ì¸ ì½˜í…ì¸ í™œì„±í™” ë˜ëŠ” 비활성화 ì „í™˜" + #: src/view/com/modals/EditImage.tsx:271 msgid "Transformations" msgstr "변형" -#: src/view/com/post-thread/PostThreadItem.tsx:685 -#: src/view/com/post-thread/PostThreadItem.tsx:687 -#: src/view/com/util/forms/PostDropdownBtn.tsx:156 +#: src/view/com/post-thread/PostThreadItem.tsx:646 +#: src/view/com/post-thread/PostThreadItem.tsx:648 +#: src/view/com/util/forms/PostDropdownBtn.tsx:212 +#: src/view/com/util/forms/PostDropdownBtn.tsx:214 msgid "Translate" msgstr "번ì—" @@ -4219,11 +4463,11 @@ msgctxt "action" msgid "Try again" msgstr "다시 시ë„" -#: src/view/screens/ProfileList.tsx:506 +#: src/view/screens/ProfileList.tsx:478 msgid "Un-block list" msgstr "리스트 차단 í•´ì œ" -#: src/view/screens/ProfileList.tsx:491 +#: src/view/screens/ProfileList.tsx:461 msgid "Un-mute list" msgstr "리스트 언뮤트" @@ -4235,21 +4479,28 @@ msgstr "리스트 언뮤트" msgid "Unable to contact your service. Please check your Internet connection." msgstr "ì„œë¹„ìŠ¤ì— ì—°ê²°í• ìˆ˜ 없습니다. ì¸í„°ë„· ì—°ê²°ì„ í™•ì¸í•˜ì„¸ìš”." -#: src/view/com/profile/ProfileHeader.tsx:433 -#: src/view/screens/ProfileList.tsx:590 +#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:174 +#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:278 +#: src/view/com/profile/ProfileMenu.tsx:361 +#: src/view/screens/ProfileList.tsx:572 msgid "Unblock" msgstr "차단 í•´ì œ" -#: src/view/com/profile/ProfileHeader.tsx:436 +#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:179 msgctxt "action" msgid "Unblock" msgstr "차단 í•´ì œ" -#: src/view/com/profile/ProfileHeader.tsx:261 -#: src/view/com/profile/ProfileHeader.tsx:345 +#: src/view/com/profile/ProfileMenu.tsx:299 +#: src/view/com/profile/ProfileMenu.tsx:305 msgid "Unblock Account" msgstr "ê³„ì • 차단 í•´ì œ" +#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:272 +#: src/view/com/profile/ProfileMenu.tsx:343 +msgid "Unblock Account?" +msgstr "ê³„ì •ì„ ì°¨ë‹¨ í•´ì œí•˜ì‹œê² ìŠµë‹ˆê¹Œ?" + #: src/view/com/modals/Repost.tsx:42 #: src/view/com/modals/Repost.tsx:55 #: src/view/com/util/post-ctrls/RepostButton.tsx:60 @@ -4257,66 +4508,84 @@ msgstr "ê³„ì • 차단 í•´ì œ" msgid "Undo repost" msgstr "재게시 취소" -#: src/view/com/profile/FollowButton.tsx:55 +#: src/view/com/profile/FollowButton.tsx:60 msgctxt "action" msgid "Unfollow" msgstr "언팔로우" -#: src/view/com/profile/ProfileHeader.tsx:485 +#: src/screens/Profile/Header/ProfileHeaderStandard.tsx:213 msgid "Unfollow {0}" msgstr "{0} ë‹˜ì„ ì–¸íŒ”ë¡œìš°" +#: src/view/com/profile/ProfileMenu.tsx:241 +#: src/view/com/profile/ProfileMenu.tsx:251 +msgid "Unfollow Account" +msgstr "ê³„ì • 언팔로우" + #: src/view/com/auth/create/state.ts:262 msgid "Unfortunately, you do not meet the requirements to create an account." msgstr "아쉽지만 ê³„ì •ì„ ë§Œë“¤ 수 있는 ìš”ê±´ì„ ì¶©ì¡±í•˜ì§€ 못했습니다." -#: src/view/com/util/post-ctrls/PostCtrls.tsx:182 -#: src/view/com/util/post-ctrls/PostCtrls.tsx:216 +#: src/view/com/util/post-ctrls/PostCtrls.tsx:185 msgid "Unlike" msgstr "좋아요 취소" -#: src/components/TagMenu/index.tsx:253 -#: src/view/screens/ProfileList.tsx:597 +#: src/view/screens/ProfileFeed.tsx:572 +msgid "Unlike this feed" +msgstr "ì´ í”¼ë“œ 좋아요 취소" + +#: src/components/TagMenu/index.tsx:249 +#: src/view/screens/ProfileList.tsx:579 msgid "Unmute" msgstr "언뮤트" -#: src/components/TagMenu/index.web.tsx:90 +#: src/components/TagMenu/index.web.tsx:104 msgid "Unmute {truncatedTag}" -msgstr "" +msgstr "{truncatedTag} 언뮤트" -#: src/view/com/profile/ProfileHeader.tsx:326 +#: src/view/com/profile/ProfileMenu.tsx:278 +#: src/view/com/profile/ProfileMenu.tsx:284 msgid "Unmute Account" msgstr "ê³„ì • 언뮤트" -#: src/components/TagMenu/index.tsx:210 -msgid "Unmute all {tag} posts" -msgstr "" +#: src/components/TagMenu/index.tsx:208 +msgid "Unmute all {displayTag} posts" +msgstr "ëª¨ë“ {tag} 게시물 언뮤트" -#: src/view/com/util/forms/PostDropdownBtn.tsx:202 +#: src/view/com/util/forms/PostDropdownBtn.tsx:251 +#: src/view/com/util/forms/PostDropdownBtn.tsx:256 msgid "Unmute thread" msgstr "ìŠ¤ë ˆë“œ 언뮤트" -#: src/view/screens/ProfileFeed.tsx:354 -#: src/view/screens/ProfileList.tsx:581 +#: src/view/screens/ProfileFeed.tsx:294 +#: src/view/screens/ProfileList.tsx:563 msgid "Unpin" msgstr "ê³ ì • í•´ì œ" -#: src/view/screens/ProfileList.tsx:474 +#: src/view/screens/ProfileFeed.tsx:291 +msgid "Unpin from home" +msgstr "홈ì—서 ê³ ì • í•´ì œ" + +#: src/view/screens/ProfileList.tsx:444 msgid "Unpin moderation list" msgstr "ê²€í† ë¦¬ìŠ¤íŠ¸ ê³ ì • í•´ì œ" -#: src/view/screens/ProfileFeed.tsx:346 -msgid "Unsave" -msgstr "ì €ìž¥ í•´ì œ" +#: src/screens/Profile/Header/ProfileHeaderLabeler.tsx:220 +msgid "Unsubscribe" +msgstr "êµ¬ë… ì·¨ì†Œ" + +#: src/screens/Profile/Header/ProfileHeaderLabeler.tsx:184 +msgid "Unsubscribe from this labeler" +msgstr "ì´ ë¼ë²¨ëŸ¬ êµ¬ë… ì·¨ì†Œí•˜ê¸°" + +#: src/lib/moderation/useReportOptions.ts:70 +msgid "Unwanted Sexual Content" +msgstr "ì›ì¹˜ 않는 성ì 콘í…ì¸ " #: src/view/com/modals/UserAddRemoveLists.tsx:70 msgid "Update {displayName} in Lists" msgstr "리스트ì—서 {displayName} ì—…ë°ì´íЏ" -#: src/lib/hooks/useOTAUpdate.ts:15 -msgid "Update Available" -msgstr "ì—…ë°ì´íЏ 사용 가능" - #: src/view/com/auth/login/SetNewPasswordForm.tsx:204 msgid "Updating..." msgstr "ì—…ë°ì´íЏ 중…" @@ -4325,7 +4594,26 @@ msgstr "ì—…ë°ì´íЏ 중…" msgid "Upload a text file to:" msgstr "í…스트 íŒŒì¼ ì—…ë¡œë“œ 경로:" -#: src/view/screens/AppPasswords.tsx:195 +#: src/view/com/util/UserAvatar.tsx:319 +#: src/view/com/util/UserAvatar.tsx:322 +#: src/view/com/util/UserBanner.tsx:113 +#: src/view/com/util/UserBanner.tsx:116 +msgid "Upload from Camera" +msgstr "ì¹´ë©”ë¼ì—서 업로드" + +#: src/view/com/util/UserAvatar.tsx:336 +#: src/view/com/util/UserBanner.tsx:130 +msgid "Upload from Files" +msgstr "파ì¼ì—서 업로드" + +#: src/view/com/util/UserAvatar.tsx:330 +#: src/view/com/util/UserAvatar.tsx:334 +#: src/view/com/util/UserBanner.tsx:124 +#: src/view/com/util/UserBanner.tsx:128 +msgid "Upload from Library" +msgstr "ë¼ì´ë¸ŒëŸ¬ë¦¬ì—서 업로드" + +#: src/view/screens/AppPasswords.tsx:197 msgid "Use app passwords to login to other Bluesky clients without giving full access to your account or password." msgstr "앱 비밀번호를 사용하면 ê³„ì •ì´ë‚˜ ë¹„ë°€ë²ˆí˜¸ì— ëŒ€í•œ ì „ì²´ ì ‘ê·¼ ê¶Œí•œì„ ì œê³µí•˜ì§€ ì•Šê³ ë„ ë‹¤ë¥¸ Bluesky í´ë¼ì´ì–¸íŠ¸ì— ë¡œê·¸ì¸í• 수 있습니다." @@ -4347,25 +4635,30 @@ msgstr "ë‚´ 기본 브ë¼ìš°ì € 사용" msgid "Use this to sign into the other app along with your handle." msgstr "ì´ ë¹„ë°€ë²ˆí˜¸ì™€ í•¸ë“¤ì„ ì‚¬ìš©í•˜ì—¬ 다른 ì•±ì— ë¡œê·¸ì¸í•˜ì„¸ìš”." -#: src/view/com/modals/ServerInput.tsx:105 -#~ msgid "Use your domain as your Bluesky client service provider" -#~ msgstr "ë‚´ ë„ë©”ì¸ì„ Bluesky í´ë¼ì´ì–¸íЏ 서비스 공급ìžë¡œ 사용합니다" - #: src/view/com/modals/InviteCodes.tsx:200 msgid "Used by:" msgstr "사용 ê³„ì •:" -#: src/view/com/modals/ModerationDetails.tsx:54 +#: src/components/moderation/ModerationDetailsDialog.tsx:65 +#: src/lib/moderation/useModerationCauseDescription.ts:56 msgid "User Blocked" msgstr "ì‚¬ìš©ìž ì°¨ë‹¨ë¨" -#: src/view/com/modals/ModerationDetails.tsx:40 +#: src/lib/moderation/useModerationCauseDescription.ts:48 +msgid "User Blocked by \"{0}\"" +msgstr " \"{0}\"ì—서 ì°¨ë‹¨ëœ ì‚¬ìš©ìž" + +#: src/components/moderation/ModerationDetailsDialog.tsx:54 msgid "User Blocked by List" msgstr "리스트로 ì‚¬ìš©ìž ì°¨ë‹¨ë¨" -#: src/view/com/modals/ModerationDetails.tsx:60 +#: src/lib/moderation/useModerationCauseDescription.ts:66 +msgid "User Blocking You" +msgstr "나를 차단한 사용ìž" + +#: src/components/moderation/ModerationDetailsDialog.tsx:71 msgid "User Blocks You" -msgstr "사용ìžê°€ 나를 차단함" +msgstr "나를 차단한 사용ìž" #: src/view/com/auth/create/Step2.tsx:79 msgid "User handle" @@ -4376,13 +4669,13 @@ msgstr "ì‚¬ìš©ìž í•¸ë“¤" msgid "User list by {0}" msgstr "{0} ë‹˜ì˜ ì‚¬ìš©ìž ë¦¬ìŠ¤íŠ¸" -#: src/view/screens/ProfileList.tsx:762 +#: src/view/screens/ProfileList.tsx:777 msgid "User list by <0/>" msgstr "<0/> ë‹˜ì˜ ì‚¬ìš©ìž ë¦¬ìŠ¤íŠ¸" #: src/view/com/lists/ListCard.tsx:83 #: src/view/com/modals/UserAddRemoveLists.tsx:196 -#: src/view/screens/ProfileList.tsx:760 +#: src/view/screens/ProfileList.tsx:775 msgid "User list by you" msgstr "ë‚´ ì‚¬ìš©ìž ë¦¬ìŠ¤íŠ¸" @@ -4403,7 +4696,7 @@ msgstr "ì‚¬ìš©ìž ë¦¬ìŠ¤íŠ¸" msgid "Username or email address" msgstr "ì‚¬ìš©ìž ì´ë¦„ ë˜ëŠ” ì´ë©”ì¼ ì£¼ì†Œ" -#: src/view/screens/ProfileList.tsx:796 +#: src/view/screens/ProfileList.tsx:811 msgid "Users" msgstr "사용ìž" @@ -4415,19 +4708,19 @@ msgstr "<0/> ë‹˜ì´ íŒ”ë¡œìš°í•œ 사용ìž" msgid "Users in \"{0}\"" msgstr "\"{0}\"ì— ìžˆëŠ” 사용ìž" -#: src/view/com/auth/create/Step2.tsx:243 -#~ msgid "Verification code" -#~ msgstr "ì¸ì¦ 코드" +#: src/components/LikesDialog.tsx:85 +msgid "Users that have liked this content or profile" +msgstr "ì´ ì½˜í…ì¸ ë˜ëŠ” í”„ë¡œí•„ì„ ì¢‹ì•„í•˜ëŠ” 사용ìž" -#: src/view/screens/Settings/index.tsx:910 +#: src/view/screens/Settings/index.tsx:938 msgid "Verify email" msgstr "ì´ë©”ì¼ ì¸ì¦" -#: src/view/screens/Settings/index.tsx:935 +#: src/view/screens/Settings/index.tsx:963 msgid "Verify my email" msgstr "ë‚´ ì´ë©”ì¼ ì¸ì¦í•˜ê¸°" -#: src/view/screens/Settings/index.tsx:944 +#: src/view/screens/Settings/index.tsx:972 msgid "Verify My Email" msgstr "ë‚´ ì´ë©”ì¼ ì¸ì¦í•˜ê¸°" @@ -4444,7 +4737,7 @@ msgstr "ì´ë©”ì¼ ì¸ì¦í•˜ê¸°" msgid "Video Games" msgstr "비디오 게임" -#: src/view/com/profile/ProfileHeader.tsx:662 +#: src/screens/Profile/Header/Shell.tsx:110 msgid "View {0}'s avatar" msgstr "{0} ë‹˜ì˜ ì•„ë°”íƒ€ë¥¼ 봅니다" @@ -4452,11 +4745,23 @@ msgstr "{0} ë‹˜ì˜ ì•„ë°”íƒ€ë¥¼ 봅니다" msgid "View debug entry" msgstr "디버그 í•목 보기" -#: src/view/com/posts/FeedSlice.tsx:103 +#: src/components/ReportDialog/SelectReportOptionView.tsx:132 +msgid "View details" +msgstr "세부 ì •ë³´ 보기" + +#: src/components/ReportDialog/SelectReportOptionView.tsx:127 +msgid "View details for reporting a copyright violation" +msgstr "ì €ìž‘ê¶Œ 위반 ì‹ ê³ ì— ëŒ€í•œ 세부 ì •ë³´ 보기" + +#: src/view/com/posts/FeedSlice.tsx:99 msgid "View full thread" msgstr "ì „ì²´ ìŠ¤ë ˆë“œ 보기" -#: src/view/com/posts/FeedErrorMessage.tsx:172 +#: src/components/moderation/LabelsOnMe.tsx:51 +msgid "View information about these labels" +msgstr "ì´ ë¼ë²¨ì— 대한 ì •ë³´ 보기" + +#: src/view/com/posts/FeedErrorMessage.tsx:166 msgid "View profile" msgstr "프로필 보기" @@ -4464,19 +4769,41 @@ msgstr "프로필 보기" msgid "View the avatar" msgstr "아바타 보기" +#: src/components/LabelingServiceCard/index.tsx:140 +msgid "View the labeling service provided by @{0}" +msgstr "{0} ë‹˜ì´ ì œê³µí•˜ëŠ” ë¼ë²¨ë§ 서비스 보기" + +#: src/view/screens/ProfileFeed.tsx:584 +msgid "View users who like this feed" +msgstr "ì´ í”¼ë“œë¥¼ 좋아하는 ì‚¬ìš©ìž ë³´ê¸°" + #: src/view/com/modals/LinkWarning.tsx:75 msgid "Visit Site" msgstr "사ì´íЏ 방문" -#: src/screens/Onboarding/StepModeration/ModerationOption.tsx:42 -#: src/view/com/modals/ContentFilteringSettings.tsx:259 +#: src/components/moderation/GlobalModerationLabelPref.tsx:44 +#: src/lib/moderation/useLabelBehaviorDescription.ts:17 +#: src/lib/moderation/useLabelBehaviorDescription.ts:22 +#: src/screens/Onboarding/StepModeration/ModerationOption.tsx:53 msgid "Warn" msgstr "ê²½ê³ " +#: src/lib/moderation/useLabelBehaviorDescription.ts:48 +msgid "Warn content" +msgstr "콘í…ì¸ ê²½ê³ " + +#: src/lib/moderation/useLabelBehaviorDescription.ts:46 +msgid "Warn content and filter from feeds" +msgstr "콘í…ì¸ ê²½ê³ ë° í”¼ë“œì—서 í•„í„°ë§" + #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:134 msgid "We also think you'll like \"For You\" by Skygaze:" msgstr "Skygazeì˜ \"For You\"를 사용해 ë³¼ ìˆ˜ë„ ìžˆìŠµë‹ˆë‹¤:" +#: src/screens/Hashtag.tsx:132 +msgid "We couldn't find any results for that hashtag." +msgstr "해당 í•´ì‹œíƒœê·¸ì— ëŒ€í•œ 결과를 ì°¾ì„ ìˆ˜ 없습니다." + #: src/screens/Deactivated.tsx:133 msgid "We estimate {estimatedTime} until your account is ready." msgstr "ê³„ì •ì´ ì¤€ë¹„ë 때까지 {estimatedTime}ì´(ê°€) 걸릴 것으로 예ìƒë©ë‹ˆë‹¤." @@ -4489,14 +4816,18 @@ msgstr "ì¦ê±°ìš´ 시간 ë˜ì‹œê¸° ë°”ëžë‹ˆë‹¤. Blueskyì˜ ë‹¤ìŒ íŠ¹ì§•ì„ ê¸° msgid "We ran out of posts from your follows. Here's the latest from <0/>." msgstr "팔로우한 사용ìžì˜ ê²Œì‹œë¬¼ì´ ë¶€ì¡±í•©ë‹ˆë‹¤. ëŒ€ì‹ <0/>ì˜ ìµœì‹ ê²Œì‹œë¬¼ì„ í‘œì‹œí•©ë‹ˆë‹¤." -#: src/components/dialogs/MutedWords.tsx:161 +#: src/components/dialogs/MutedWords.tsx:204 msgid "We recommend avoiding common words that appear in many posts, since it can result in no posts being shown." -msgstr "" +msgstr "ê²Œì‹œë¬¼ì´ í‘œì‹œë˜ì§€ ì•Šì„ ìˆ˜ 있으므로 ë§Žì€ ê²Œì‹œë¬¼ì— ìžì£¼ 등장하는 단어는 피하는 ê²ƒì´ ì¢‹ìŠµë‹ˆë‹¤." #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:124 msgid "We recommend our \"Discover\" feed:" msgstr "\"Discover\" 피드를 권장합니다:" +#: src/screens/Moderation/index.tsx:391 +msgid "We were unable to load your configured labelers at this time." +msgstr "현재 êµ¬ì„±ëœ ë¼ë²¨ëŸ¬ë¥¼ 불러올 수 없습니다." + #: src/screens/Onboarding/StepInterests/index.tsx:133 msgid "We weren't able to connect. Please try again to continue setting up your account. If it continues to fail, you can skip this flow." msgstr "연결하지 못했습니다. ê³„ì • ì„¤ì •ì„ ê³„ì†í•˜ë ¤ë©´ 다시 시ë„í•´ 주세요. ê³„ì† ì‹¤íŒ¨í•˜ë©´ ì´ ê³¼ì •ì„ ê±´ë„ˆë›¸ 수 있습니다." @@ -4505,48 +4836,45 @@ msgstr "연결하지 못했습니다. ê³„ì • ì„¤ì •ì„ ê³„ì†í•˜ë ¤ë©´ 다시 ì‹ msgid "We will let you know when your account is ready." msgstr "ê³„ì •ì´ ì¤€ë¹„ë˜ë©´ ì•Œë ¤ë“œë¦¬ê² ìŠµë‹ˆë‹¤." -#: src/view/com/modals/AppealLabel.tsx:48 -msgid "We'll look into your appeal promptly." -msgstr "ì´ì˜ì‹ ì²ì„ 즉시 ê²€í† í•˜ê² ìŠµë‹ˆë‹¤." - #: src/screens/Onboarding/StepInterests/index.tsx:138 msgid "We'll use this to help customize your experience." msgstr "ì´ë¥¼ 통해 ì‚¬ìš©ìž í™˜ê²½ì„ ë§žì¶¤ ì„¤ì •í• ìˆ˜ 있습니다." #: src/view/com/auth/create/CreateAccount.tsx:134 msgid "We're so excited to have you join us!" -msgstr "ë‹¹ì‹ ê³¼ 함께하게 ë˜ì–´ ì •ë§ ê¸°ì˜ë„¤ìš”!" +msgstr "함께하게 ë˜ì–´ ì •ë§ ê¸°ë»ìš”!" -#: src/view/screens/ProfileList.tsx:86 +#: src/view/screens/ProfileList.tsx:89 msgid "We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @{handleOrDid}." msgstr "죄송하지만 ì´ ë¦¬ìŠ¤íŠ¸ë¥¼ 불러올 수 없습니다. ì´ ë¬¸ì œê°€ 계ì†ë˜ë©´ 리스트 작성ìžì¸ @{handleOrDid}ì—게 문ì˜í•˜ì„¸ìš”." -#: src/components/dialogs/MutedWords.tsx:182 +#: src/components/dialogs/MutedWords.tsx:230 msgid "We're sorry, but we weren't able to load your muted words at this time. Please try again." -msgstr "" +msgstr "죄송하지만 현재 뮤트한 단어를 불러올 수 없습니다. 다시 시ë„í•´ 주세요." #: src/view/screens/Search/Search.tsx:254 msgid "We're sorry, but your search could not be completed. Please try again in a few minutes." msgstr "죄송하지만 ê²€ìƒ‰ì„ ì™„ë£Œí• ìˆ˜ 없습니다. 몇 ë¶„ í›„ì— ë‹¤ì‹œ 시ë„í•´ 주세요." +#: src/components/Lists.tsx:210 #: src/view/screens/NotFound.tsx:48 msgid "We're sorry! We can't find the page you were looking for." msgstr "죄송합니다. 페ì´ì§€ë¥¼ ì°¾ì„ ìˆ˜ 없습니다." +#: src/screens/Profile/Header/ProfileHeaderLabeler.tsx:319 +msgid "We're sorry! You can only subscribe to ten labelers, and you've reached your limit of ten." +msgstr "죄송합니다. ë¼ë²¨ëŸ¬ëŠ” 10개까지만 구ë…í• ìˆ˜ 있으며 10ê°œì— ë„달했습니다." + #: src/view/com/auth/onboarding/WelcomeMobile.tsx:46 msgid "Welcome to <0>Bluesky</0>" msgstr "<0>Bluesky</0>ì— ì˜¤ì‹ ê²ƒì„ í™˜ì˜í•©ë‹ˆë‹¤" #: src/screens/Onboarding/StepInterests/index.tsx:130 msgid "What are your interests?" -msgstr "관심사가 어떻게 ë˜ë‚˜ìš”?" - -#: src/view/com/modals/report/Modal.tsx:169 -msgid "What is the issue with this {collectionName}?" -msgstr "ì´ {collectionName}ì— ì–´ë–¤ ë¬¸ì œê°€ 있나요?" +msgstr "ì–´ë–¤ 관심사가 ìžˆìœ¼ì‹ ê°€ìš”?" #: src/view/com/auth/SplashScreen.tsx:59 -#: src/view/com/composer/Composer.tsx:286 +#: src/view/com/composer/Composer.tsx:295 msgid "What's up?" msgstr "무슨 ì¼ì´ ì¼ì–´ë‚˜ê³ 있나요?" @@ -4563,15 +4891,39 @@ msgstr "ì•Œê³ ë¦¬ì¦˜ í”¼ë“œì— ì–´ë–¤ 언어를 í‘œì‹œí•˜ì‹œê² ìŠµë‹ˆê¹Œ?" msgid "Who can reply" msgstr "ë‹µê¸€ì„ ë‹¬ 수 있는 사람" +#: src/components/ReportDialog/SelectLabelerView.tsx:33 +msgid "Who do you want to send this report to?" +msgstr "ì´ ì‹ ê³ ë¥¼ 누구ì—게 ë³´ë‚´ì‹œê² ìŠµë‹ˆê¹Œ?" + +#: src/components/ReportDialog/SelectReportOptionView.tsx:43 +msgid "Why should this content be reviewed?" +msgstr "ì´ ì½˜í…ì¸ ë¥¼ ê²€í† í•´ì•¼ 하는 ì´ìœ 는 무엇ì¸ê°€ìš”?" + +#: src/components/ReportDialog/SelectReportOptionView.tsx:56 +msgid "Why should this feed be reviewed?" +msgstr "ì´ í”¼ë“œë¥¼ ê²€í† í•´ì•¼ 하는 ì´ìœ 는 무엇ì¸ê°€ìš”?" + +#: src/components/ReportDialog/SelectReportOptionView.tsx:53 +msgid "Why should this list be reviewed?" +msgstr "ì´ ë¦¬ìŠ¤íŠ¸ë¥¼ ê²€í† í•´ì•¼ 하는 ì´ìœ 는 무엇ì¸ê°€ìš”?" + +#: src/components/ReportDialog/SelectReportOptionView.tsx:50 +msgid "Why should this post be reviewed?" +msgstr "ì´ ê²Œì‹œë¬¼ì„ ê²€í† í•´ì•¼ 하는 ì´ìœ 는 무엇ì¸ê°€ìš”?" + +#: src/components/ReportDialog/SelectReportOptionView.tsx:47 +msgid "Why should this user be reviewed?" +msgstr "ì´ ì‚¬ìš©ìžë¥¼ ê²€í† í•´ì•¼ 하는 ì´ìœ 는 무엇ì¸ê°€ìš”?" + #: src/view/com/modals/crop-image/CropImage.web.tsx:102 msgid "Wide" msgstr "가로" -#: src/view/com/composer/Composer.tsx:422 +#: src/view/com/composer/Composer.tsx:431 msgid "Write post" msgstr "게시물 작성" -#: src/view/com/composer/Composer.tsx:285 +#: src/view/com/composer/Composer.tsx:294 #: src/view/com/composer/Prompt.tsx:33 msgid "Write your reply" msgstr "답글 작성하기" @@ -4580,10 +4932,6 @@ msgstr "답글 작성하기" msgid "Writers" msgstr "작가" -#: src/view/com/auth/create/Step2.tsx:263 -#~ msgid "XXXXXX" -#~ msgstr "XXXXXX" - #: src/view/com/composer/select-language/SuggestedLanguage.tsx:77 #: src/view/screens/PreferencesFollowingFeed.tsx:129 #: src/view/screens/PreferencesFollowingFeed.tsx:201 @@ -4628,11 +4976,13 @@ msgstr "ì €ìž¥ëœ í”¼ë“œê°€ 없습니다!" msgid "You don't have any saved feeds." msgstr "ì €ìž¥ëœ í”¼ë“œê°€ 없습니다." -#: src/view/com/post-thread/PostThread.tsx:465 +#: src/view/com/post-thread/PostThread.tsx:466 msgid "You have blocked the author or you have been blocked by the author." msgstr "작성ìžë¥¼ 차단했거나 작성ìžê°€ 나를 차단했습니다." -#: src/view/com/modals/ModerationDetails.tsx:56 +#: src/components/moderation/ModerationDetailsDialog.tsx:67 +#: src/lib/moderation/useModerationCauseDescription.ts:50 +#: src/lib/moderation/useModerationCauseDescription.ts:58 msgid "You have blocked this user. You cannot view their content." msgstr "ì´ ì‚¬ìš©ìžë¥¼ 차단했습니다. 해당 사용ìžì˜ 콘í…ì¸ ë¥¼ ë³¼ 수 없습니다." @@ -4641,11 +4991,24 @@ msgstr "ì´ ì‚¬ìš©ìžë¥¼ 차단했습니다. 해당 사용ìžì˜ 콘í…ì¸ ë¥¼ ë³ #: src/view/com/modals/ChangePassword.tsx:87 #: src/view/com/modals/ChangePassword.tsx:121 msgid "You have entered an invalid code. It should look like XXXXX-XXXXX." -msgstr "" +msgstr "ìž˜ëª»ëœ ì½”ë“œë¥¼ ìž…ë ¥í–ˆìŠµë‹ˆë‹¤. XXXXX-XXXXX와 ê°™ì€ í˜•ì‹ì´ì–´ì•¼ 합니다." + +#: src/lib/moderation/useModerationCauseDescription.ts:109 +msgid "You have hidden this post" +msgstr "ë‚´ê°€ ì´ ê²Œì‹œë¬¼ì„ ìˆ¨ê²¼ìŠµë‹ˆë‹¤" + +#: src/components/moderation/ModerationDetailsDialog.tsx:102 +msgid "You have hidden this post." +msgstr "ë‚´ê°€ ì´ ê²Œì‹œë¬¼ì„ ìˆ¨ê²¼ìŠµë‹ˆë‹¤." -#: src/view/com/modals/ModerationDetails.tsx:87 -msgid "You have muted this user." -msgstr "ì´ ì‚¬ìš©ìžë¥¼ 뮤트했습니다." +#: src/components/moderation/ModerationDetailsDialog.tsx:95 +#: src/lib/moderation/useModerationCauseDescription.ts:92 +msgid "You have muted this account." +msgstr "ë‚´ê°€ ì´ ê³„ì •ì„ ë®¤íŠ¸í–ˆìŠµë‹ˆë‹¤." + +#: src/lib/moderation/useModerationCauseDescription.ts:86 +msgid "You have muted this user" +msgstr "ë‚´ê°€ ì´ ì‚¬ìš©ìžë¥¼ 뮤트했습니다" #: src/view/com/feeds/ProfileFeedgens.tsx:136 msgid "You have no feeds." @@ -4660,7 +5023,7 @@ msgstr "리스트가 없습니다." msgid "You have not blocked any accounts yet. To block an account, go to their profile and selected \"Block account\" from the menu on their account." msgstr "ì•„ì§ ì–´ë–¤ ê³„ì •ë„ ì°¨ë‹¨í•˜ì§€ 않았습니다. ê³„ì •ì„ ì°¨ë‹¨í•˜ë ¤ë©´ 해당 ê³„ì •ì˜ í”„ë¡œí•„ë¡œ ì´ë™í•˜ì—¬ ê³„ì • 메뉴ì—서 \"ê³„ì • 차단\"ì„ ì„ íƒí•˜ì„¸ìš”." -#: src/view/screens/AppPasswords.tsx:87 +#: src/view/screens/AppPasswords.tsx:89 msgid "You have not created any app passwords yet. You can create one by pressing the button below." msgstr "ì•„ì§ ì•± 비밀번호를 ìƒì„±í•˜ì§€ 않았습니다. 아래 ë²„íŠ¼ì„ ëˆŒëŸ¬ ìƒì„±í• 수 있습니다." @@ -4668,23 +5031,27 @@ msgstr "ì•„ì§ ì•± 비밀번호를 ìƒì„±í•˜ì§€ 않았습니다. 아래 버튼ì msgid "You have not muted any accounts yet. To mute an account, go to their profile and selected \"Mute account\" from the menu on their account." msgstr "ì•„ì§ ì–´ë–¤ ê³„ì •ë„ ë®¤íŠ¸í•˜ì§€ 않았습니다. ê³„ì •ì„ ë®¤íŠ¸í•˜ë ¤ë©´ 해당 ê³„ì •ì˜ í”„ë¡œí•„ë¡œ ì´ë™í•˜ì—¬ ê³„ì • 메뉴ì—서 \"ê³„ì • 뮤트\"를 ì„ íƒí•˜ì„¸ìš”." -#: src/components/dialogs/MutedWords.tsx:202 +#: src/components/dialogs/MutedWords.tsx:250 msgid "You haven't muted any words or tags yet" -msgstr "" +msgstr "ì•„ì§ ì–´ë–¤ 단어나 íƒœê·¸ë„ ë®¤íŠ¸í•˜ì§€ 않았습니다" -#: src/view/com/modals/ContentFilteringSettings.tsx:175 -msgid "You must be 18 or older to enable adult content." -msgstr "ì„±ì¸ ì½˜í…ì¸ ë¥¼ í™œì„±í™”í•˜ë ¤ë©´ 18세 ì´ìƒì´ì–´ì•¼ 합니다." +#: src/components/moderation/LabelsOnMeDialog.tsx:69 +msgid "You may appeal these labels if you feel they were placed in error." +msgstr "ì´ ë¼ë²¨ì´ 잘못 ì§€ì •ë˜ì—ˆë‹¤ê³ ìƒê°ë˜ë©´ ì´ì˜ì‹ ì²í• 수 있습니다." -#: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:103 +#: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:108 msgid "You must be 18 years or older to enable adult content" msgstr "ì„±ì¸ ì½˜í…ì¸ ë¥¼ ì‚¬ìš©í•˜ë ¤ë©´ ë§Œ 18세 ì´ìƒì´ì–´ì•¼ 합니다." -#: src/view/com/util/forms/PostDropdownBtn.tsx:129 +#: src/components/ReportDialog/SubmitView.tsx:205 +msgid "You must select at least one labeler for a report" +msgstr "ì‹ ê³ í•˜ë ¤ë©´ 하나 ì´ìƒì˜ ë¼ë²¨ì„ ì„ íƒí•´ì•¼ 합니다." + +#: src/view/com/util/forms/PostDropdownBtn.tsx:144 msgid "You will no longer receive notifications for this thread" msgstr "ì´ ìŠ¤ë ˆë“œì— ëŒ€í•œ ì•Œë¦¼ì„ ë” ì´ìƒ 받지 않습니다" -#: src/view/com/util/forms/PostDropdownBtn.tsx:132 +#: src/view/com/util/forms/PostDropdownBtn.tsx:147 msgid "You will now receive notifications for this thread" msgstr "ì´ì œ ì´ ìŠ¤ë ˆë“œì— ëŒ€í•œ ì•Œë¦¼ì„ ë°›ìŠµë‹ˆë‹¤" @@ -4692,7 +5059,7 @@ msgstr "ì´ì œ ì´ ìŠ¤ë ˆë“œì— ëŒ€í•œ ì•Œë¦¼ì„ ë°›ìŠµë‹ˆë‹¤" msgid "You will receive an email with a \"reset code.\" Enter that code here, then enter your new password." msgstr "\"ìž¬ì„¤ì • 코드\"ê°€ í¬í•¨ëœ ì´ë©”ì¼ì„ 받게 ë˜ë©´ ì—¬ê¸°ì— í•´ë‹¹ 코드를 ìž…ë ¥í•œ ë‹¤ìŒ ìƒˆ 비밀번호를 ìž…ë ¥í•©ë‹ˆë‹¤." -#: src/screens/Onboarding/StepModeration/index.tsx:72 +#: src/screens/Onboarding/StepModeration/index.tsx:59 msgid "You're in control" msgstr "ì§ì ‘ ì œì–´í•˜ì„¸ìš”" @@ -4706,11 +5073,16 @@ msgstr "대기 중입니다" msgid "You're ready to go!" msgstr "준비가 ë났습니다!" +#: src/components/moderation/ModerationDetailsDialog.tsx:99 +#: src/lib/moderation/useModerationCauseDescription.ts:101 +msgid "You've chosen to hide a word or tag within this post." +msgstr "ì´ ê¸€ì—서 단어 ë˜ëŠ” 태그를 숨기ë„ë¡ ì„¤ì •í–ˆìŠµë‹ˆë‹¤." + #: src/view/com/posts/FollowingEndOfFeed.tsx:48 msgid "You've reached the end of your feed! Find some more accounts to follow." msgstr "피드 ëì— ë„달했습니다! íŒ”ë¡œìš°í• ê³„ì •ì„ ë” ì°¾ì•„ë³´ì„¸ìš”." -#: src/view/com/auth/create/Step1.tsx:74 +#: src/view/com/auth/create/Step1.tsx:67 msgid "Your account" msgstr "ë‚´ ê³„ì •" @@ -4720,9 +5092,9 @@ msgstr "ê³„ì •ì„ ì‚ì œí–ˆìŠµë‹ˆë‹¤" #: src/view/screens/Settings/ExportCarDialog.tsx:47 msgid "Your account repository, containing all public data records, can be downloaded as a \"CAR\" file. This file does not include media embeds, such as images, or your private data, which must be fetched separately." -msgstr "" +msgstr "ëª¨ë“ ê³µê°œ ë°ì´í„° ë ˆì½”ë“œê°€ í¬í•¨ëœ ê³„ì • ì €ìž¥ì†Œë¥¼ \"CAR\" 파ì¼ë¡œ ë‹¤ìš´ë¡œë“œí• ìˆ˜ 있습니다. ì´ íŒŒì¼ì—는 ì´ë¯¸ì§€ì™€ ê°™ì€ ë¯¸ë””ì–´ ìž„ë² ë“œë‚˜ 별ë„로 ê°€ì ¸ì™€ì•¼ 하는 비공개 ë°ì´í„°ëŠ” í¬í•¨ë˜ì§€ 않습니다." -#: src/view/com/auth/create/Step1.tsx:238 +#: src/view/com/auth/create/Step1.tsx:215 msgid "Your birth date" msgstr "ìƒë…„ì›”ì¼" @@ -4740,10 +5112,6 @@ msgstr "기본 피드는 \"팔로우 중\"입니다" msgid "Your email appears to be invalid." msgstr "ì´ë©”ì¼ì´ ìž˜ëª»ëœ ê²ƒ 같습니다." -#: src/view/com/modals/Waitlist.tsx:109 -msgid "Your email has been saved! We'll be in touch soon." -msgstr "ì´ë©”ì¼ì´ ì €ìž¥ë˜ì—ˆìŠµë‹ˆë‹¤! 가까운 ì‹œì¼ ë‚´ì— ì—°ë½ë“œë¦¬ê² 습니다." - #: src/view/com/modals/ChangeEmail.tsx:125 msgid "Your email has been updated but not verified. As a next step, please verify your new email." msgstr "ì´ë©”ì¼ì´ 변경ë˜ì—ˆì§€ë§Œ ì¸ì¦ë˜ì§€ 않았습니다. ë‹¤ìŒ ë‹¨ê³„ë¡œ 새 ì´ë©”ì¼ì„ ì¸ì¦í•´ 주세요." @@ -4754,7 +5122,7 @@ msgstr "ì´ë©”ì¼ì´ ì•„ì§ ì¸ì¦ë˜ì§€ 않았습니다. ì´ëŠ” 중요한 ë³´ì• #: src/view/com/posts/FollowingEmptyState.tsx:47 msgid "Your following feed is empty! Follow more users to see what's happening." -msgstr "팔로우 ì¤‘ì¸ í”¼ë“œê°€ 비어 있습니다! ë” ë§Žì€ ì‚¬ìš©ìžë¥¼ 팔로우하여 무슨 ì¼ì´ ì¼ì–´ë‚˜ê³ 있는지 확ì¸í•˜ì„¸ìš”." +msgstr "팔로우 중 피드가 비어 있습니다! ë” ë§Žì€ ì‚¬ìš©ìžë¥¼ 팔로우하여 무슨 ì¼ì´ ì¼ì–´ë‚˜ê³ 있는지 확ì¸í•˜ì„¸ìš”." #: src/view/com/auth/create/Step2.tsx:83 msgid "Your full handle will be" @@ -4764,21 +5132,15 @@ msgstr "ë‚´ ì „ì²´ 핸들:" msgid "Your full handle will be <0>@{0}</0>" msgstr "ë‚´ ì „ì²´ 핸들: <0>@{0}</0>" -#: src/view/screens/Settings.tsx:430 -#: src/view/shell/desktop/RightNav.tsx:137 -#: src/view/shell/Drawer.tsx:660 -#~ msgid "Your invite codes are hidden when logged in using an App Password" -#~ msgstr "앱 비밀번호를 사용하여 로그ì¸í•˜ë©´ 초대 코드가 숨겨집니다" - -#: src/components/dialogs/MutedWords.tsx:173 +#: src/components/dialogs/MutedWords.tsx:221 msgid "Your muted words" -msgstr "" +msgstr "뮤트한 단어" #: src/view/com/modals/ChangePassword.tsx:155 msgid "Your password has been changed successfully!" -msgstr "" +msgstr "비밀번호를 성공ì 으로 변경했습니다." -#: src/view/com/composer/Composer.tsx:274 +#: src/view/com/composer/Composer.tsx:283 msgid "Your post has been published" msgstr "ê²Œì‹œë¬¼ì„ ê²Œì‹œí–ˆìŠµë‹ˆë‹¤" @@ -4789,11 +5151,11 @@ msgid "Your posts, likes, and blocks are public. Mutes are private." msgstr "게시물, 좋아요, 차단 목ë¡ì€ 공개ë©ë‹ˆë‹¤. 뮤트 목ë¡ì€ 공개ë˜ì§€ 않습니다." #: src/view/com/modals/SwitchAccount.tsx:84 -#: src/view/screens/Settings/index.tsx:118 +#: src/view/screens/Settings/index.tsx:122 msgid "Your profile" msgstr "ë‚´ 프로필" -#: src/view/com/composer/Composer.tsx:273 +#: src/view/com/composer/Composer.tsx:282 msgid "Your reply has been published" msgstr "ë‚´ ë‹µê¸€ì„ ê²Œì‹œí–ˆìŠµë‹ˆë‹¤" diff --git a/src/locale/locales/pt-BR/messages.po b/src/locale/locales/pt-BR/messages.po index ff5d7e55d..bfd794c55 100644 --- a/src/locale/locales/pt-BR/messages.po +++ b/src/locale/locales/pt-BR/messages.po @@ -8,8 +8,8 @@ msgstr "" "Language: pt-BR\n" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2024-02-08 19:59\n" -"Last-Translator: maisondasilva\n" +"PO-Revision-Date: 2024-03-12 11:36\n" +"Last-Translator: gildaswise\n" "Language-Team: maisondasilva, MightyLoggor, gildaswise, gleydson, faeriarum\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" @@ -17,28 +17,10 @@ msgstr "" msgid "(no email)" msgstr "(sem email)" -#: src/view/shell/desktop/RightNav.tsx:168 -#~ msgid "{0, plural, one {# invite code available} other {# invite codes available}}" -#~ msgstr "{0, plural, one {# convite disponÃvel} other {# convites disponÃveis}}" - #: src/view/com/profile/ProfileHeader.tsx:593 msgid "{following} following" msgstr "{following} seguindo" -#: src/view/shell/desktop/RightNav.tsx:151 -#~ msgid "{invitesAvailable, plural, one {Invite codes: # available} other {Invite codes: # available}}" -#~ msgstr "{invitesAvailable, plural, one {Convites: # disponÃvel} other {Convites: # disponÃveis}}" - -#: src/view/screens/Settings.tsx:435 -#: src/view/shell/Drawer.tsx:664 -#~ msgid "{invitesAvailable} invite code available" -#~ msgstr "{invitesAvailable} convite disponÃvel" - -#: src/view/screens/Settings.tsx:437 -#: src/view/shell/Drawer.tsx:666 -#~ msgid "{invitesAvailable} invite codes available" -#~ msgstr "{invitesAvailable} convites disponÃveis" - #: src/view/shell/Drawer.tsx:440 msgid "{numUnreadNotifications} unread" msgstr "{numUnreadNotifications} não lidas" @@ -75,12 +57,12 @@ msgstr "Um aviso de conteúdo foi aplicado a este {0}." msgid "A new version of the app is available. Please update to continue using the app." msgstr "Uma nova versão do aplicativo está disponÃvel. Por favor, atualize para continuar usando o aplicativo." -#: src/view/com/util/ViewHeader.tsx:83 +#: src/view/com/util/ViewHeader.tsx:89 #: src/view/screens/Search/Search.tsx:647 msgid "Access navigation links and settings" msgstr "Acessar links de navegação e configurações" -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:51 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:52 msgid "Access profile and other navigation links" msgstr "Acessar perfil e outros links de navegação" @@ -127,11 +109,11 @@ msgstr "Conta desbloqueada" msgid "Account unmuted" msgstr "Conta dessilenciada" -#: src/components/dialogs/MutedWords.tsx:147 +#: src/components/dialogs/MutedWords.tsx:165 #: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:150 #: src/view/com/modals/ListAddRemoveUsers.tsx:264 #: src/view/com/modals/UserAddRemoveLists.tsx:219 -#: src/view/screens/ProfileList.tsx:812 +#: src/view/screens/ProfileList.tsx:813 msgid "Add" msgstr "Adicionar" @@ -139,7 +121,7 @@ msgstr "Adicionar" msgid "Add a content warning" msgstr "Adicionar um aviso de conteúdo" -#: src/view/screens/ProfileList.tsx:802 +#: src/view/screens/ProfileList.tsx:803 msgid "Add a user to this list" msgstr "Adicionar um usuário a esta lista" @@ -177,13 +159,13 @@ msgstr "Adicionar prévia de link" msgid "Add link card:" msgstr "Adicionar prévia de link:" -#: src/components/dialogs/MutedWords.tsx:140 +#: src/components/dialogs/MutedWords.tsx:158 msgid "Add mute word for configured settings" -msgstr "" +msgstr "Adicionar palavra silenciada para as configurações selecionadas" -#: src/components/dialogs/MutedWords.tsx:74 +#: src/components/dialogs/MutedWords.tsx:87 msgid "Add muted words and tags" -msgstr "" +msgstr "Adicionar palavras/tags silenciadas" #: src/view/com/modals/ChangeHandle.tsx:417 msgid "Add the following DNS record to your domain:" @@ -223,17 +205,13 @@ msgstr "Conteúdo Adulto" msgid "Adult content can only be enabled via the Web at <0/>." msgstr "Conteúdo adulto só pode ser habilitado no site: <0/>." -#: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:78 -#~ msgid "Adult content can only be enabled via the Web at <0>bsky.app</0>." -#~ msgstr "Conteúdo adulto só pode ser habilitado no site: <0>bsky.app</0>." - #: src/view/screens/Settings/index.tsx:664 msgid "Advanced" msgstr "Avançado" #: src/view/screens/Feeds.tsx:666 msgid "All the feeds you've saved, right in one place." -msgstr "" +msgstr "Todos os feeds que você salvou, em um único lugar." #: src/view/com/auth/login/ForgotPasswordForm.tsx:221 #: src/view/com/modals/ChangePassword.tsx:168 @@ -269,7 +247,7 @@ msgstr "Um email foi enviado para seu email anterior, {0}. Ele inclui um código msgid "An issue occurred, please try again." msgstr "Ocorreu um problema, por favor tente novamente." -#: src/view/com/notifications/FeedItem.tsx:236 +#: src/view/com/notifications/FeedItem.tsx:237 #: src/view/com/threadgate/WhoCanReply.tsx:178 msgid "and" msgstr "e" @@ -302,13 +280,14 @@ msgstr "Configurações de Senha de Aplicativo" #~ msgid "App passwords" #~ msgstr "Senhas de aplicativos" -#: src/Navigation.tsx:237 +#: src/Navigation.tsx:239 #: src/view/screens/AppPasswords.tsx:187 #: src/view/screens/Settings/index.tsx:684 msgid "App Passwords" msgstr "Senhas de Aplicativos" -#: src/view/com/util/forms/PostDropdownBtn.tsx:295 +#: src/view/com/util/forms/PostDropdownBtn.tsx:337 +#: src/view/com/util/forms/PostDropdownBtn.tsx:346 msgid "Appeal content warning" msgstr "Contestar aviso de conteúdo" @@ -336,12 +315,12 @@ msgstr "Tem certeza de que deseja excluir a senha do aplicativo \"{name}\"?" msgid "Are you sure you'd like to discard this draft?" msgstr "Tem certeza que deseja descartar este rascunho?" -#: src/components/dialogs/MutedWords.tsx:233 +#: src/components/dialogs/MutedWords.tsx:282 #: src/view/screens/ProfileList.tsx:365 msgid "Are you sure?" msgstr "Tem certeza?" -#: src/view/com/util/forms/PostDropdownBtn.tsx:278 +#: src/view/com/util/forms/PostDropdownBtn.tsx:322 msgid "Are you sure? This cannot be undone." msgstr "Tem certeza? Esta ação não poderá ser desfeita." @@ -367,7 +346,7 @@ msgstr "Nudez artÃstica ou não erótica." #: src/view/com/post-thread/PostThread.tsx:522 #: src/view/com/post-thread/PostThread.tsx:530 #: src/view/com/profile/ProfileHeader.tsx:649 -#: src/view/com/util/ViewHeader.tsx:81 +#: src/view/com/util/ViewHeader.tsx:87 msgid "Back" msgstr "Voltar" @@ -384,7 +363,7 @@ msgstr "Com base no seu interesse em {interestsText}" msgid "Basics" msgstr "Básicos" -#: src/view/com/auth/create/Step1.tsx:250 +#: src/view/com/auth/create/Step1.tsx:227 #: src/view/com/modals/BirthDateSettings.tsx:73 msgid "Birthday" msgstr "Aniversário" @@ -423,7 +402,7 @@ msgstr "Bloqueado" msgid "Blocked accounts" msgstr "Contas bloqueadas" -#: src/Navigation.tsx:130 +#: src/Navigation.tsx:132 #: src/view/screens/ModerationBlockedAccounts.tsx:107 msgid "Blocked Accounts" msgstr "Contas Bloqueadas" @@ -457,7 +436,7 @@ msgstr "Bluesky" #: src/view/com/auth/server-input/index.tsx:150 msgid "Bluesky is an open network where you can choose your hosting provider. Custom hosting is now available in beta for developers." -msgstr "" +msgstr "Bluesky é uma rede aberta que permite a escolha do seu provedor de hospedagem. Desenvolvedores já conseguem utilizar a versão beta de hospedagem própria." #: src/view/com/auth/onboarding/WelcomeDesktop.tsx:80 #: src/view/com/auth/onboarding/WelcomeMobile.tsx:80 @@ -475,17 +454,13 @@ msgid "Bluesky is public." msgstr "Bluesky é público." #: src/view/com/modals/Waitlist.tsx:70 -msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon." -msgstr "O Bluesky usa convites para criar uma comunidade mais saudável. Se você não conhece ninguém que tenha um convite, inscreva-se na lista de espera e em breve enviaremos um para você." +#~ msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon." +#~ msgstr "O Bluesky usa convites para criar uma comunidade mais saudável. Se você não conhece ninguém que tenha um convite, inscreva-se na lista de espera e em breve enviaremos um para você." #: src/view/screens/Moderation.tsx:245 msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private." msgstr "O Bluesky não mostrará seu perfil e publicações para usuários desconectados. Outros aplicativos podem não honrar esta solicitação. Isso não torna a sua conta privada." -#: src/view/com/modals/ServerInput.tsx:78 -#~ msgid "Bluesky.Social" -#~ msgstr "Bluesky.Social" - #: src/screens/Onboarding/index.tsx:33 msgid "Books" msgstr "Livros" @@ -499,10 +474,6 @@ msgstr "Versão {0} {1}" msgid "Business" msgstr "Empresarial" -#: src/view/com/modals/ServerInput.tsx:115 -#~ msgid "Button disabled. Input custom domain to proceed." -#~ msgstr "Botão desabilitado. Utilize um domÃnio personalizado para continuar." - #: src/view/com/profile/ProfileSubpageHeader.tsx:157 msgid "by —" msgstr "por -" @@ -529,7 +500,7 @@ msgstr "Câmera" msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must be at least 4 characters long, but no more than 32 characters long." msgstr "Só pode conter letras, números, espaços, traços e sublinhados. Deve ter pelo menos 4 caracteres, mas não mais de 32 caracteres." -#: src/components/Prompt.tsx:91 +#: src/components/Prompt.tsx:101 #: src/view/com/composer/Composer.tsx:307 #: src/view/com/composer/Composer.tsx:312 #: src/view/com/modals/ChangeEmail.tsx:218 @@ -544,7 +515,6 @@ msgstr "Só pode conter letras, números, espaços, traços e sublinhados. Deve #: src/view/com/modals/Repost.tsx:87 #: src/view/com/modals/VerifyEmail.tsx:247 #: src/view/com/modals/VerifyEmail.tsx:253 -#: src/view/com/modals/Waitlist.tsx:142 #: src/view/screens/Search/Search.tsx:716 #: src/view/shell/desktop/Search.tsx:238 msgid "Cancel" @@ -586,8 +556,8 @@ msgid "Cancel search" msgstr "Cancelar busca" #: src/view/com/modals/Waitlist.tsx:136 -msgid "Cancel waitlist signup" -msgstr "Cancelar inscrição na lista de espera" +#~ msgid "Cancel waitlist signup" +#~ msgstr "Cancelar inscrição na lista de espera" #: src/view/screens/Settings/index.tsx:334 msgctxt "action" @@ -666,14 +636,10 @@ msgid "Choose the algorithms that power your experience with custom feeds." msgstr "Escolha os algoritmos que fazem sentido para você com os feeds personalizados." #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:103 -#~ msgid "Choose your algorithmic feeds" -#~ msgstr "Escolha seus feeds algoritmicos" - -#: src/screens/Onboarding/StepAlgoFeeds/index.tsx:103 msgid "Choose your main feeds" msgstr "Escolha seus feeds principais" -#: src/view/com/auth/create/Step1.tsx:219 +#: src/view/com/auth/create/Step1.tsx:196 msgid "Choose your password" msgstr "Escolha sua senha" @@ -704,10 +670,13 @@ msgstr "Limpar busca" msgid "click here" msgstr "clique aqui" -#: src/components/RichText.tsx:189 -#: src/components/TagMenu/index.web.tsx:125 +#: src/components/TagMenu/index.web.tsx:138 msgid "Click here to open tag menu for {tag}" -msgstr "" +msgstr "Clique aqui para abrir o menu da tag {tag}" + +#: src/components/RichText.tsx:191 +msgid "Click here to open tag menu for #{tag}" +msgstr "Clique aqui para abrir o menu da tag #{tag}" #: src/screens/Onboarding/index.tsx:35 msgid "Climate" @@ -718,8 +687,8 @@ msgstr "Clima e tempo" msgid "Close" msgstr "Fechar" -#: src/components/Dialog/index.web.tsx:80 -#: src/components/Dialog/index.web.tsx:194 +#: src/components/Dialog/index.web.tsx:84 +#: src/components/Dialog/index.web.tsx:198 msgid "Close active dialog" msgstr "Fechar janela ativa" @@ -743,9 +712,9 @@ msgstr "Fechar visualizador de imagens" msgid "Close navigation footer" msgstr "Fechar o painel de navegação" -#: src/components/TagMenu/index.tsx:266 +#: src/components/TagMenu/index.tsx:262 msgid "Close this dialog" -msgstr "" +msgstr "Fechar esta janela" #: src/view/shell/index.web.tsx:52 msgid "Closes bottom navigation bar" @@ -763,7 +732,7 @@ msgstr "Fecha o editor de post e descarta o rascunho" msgid "Closes viewer for header image" msgstr "Fechar o visualizador de banner" -#: src/view/com/notifications/FeedItem.tsx:317 +#: src/view/com/notifications/FeedItem.tsx:318 msgid "Collapses list of users for a given notification" msgstr "Fecha lista de usuários da notificação" @@ -775,7 +744,7 @@ msgstr "Comédia" msgid "Comics" msgstr "Quadrinhos" -#: src/Navigation.tsx:227 +#: src/Navigation.tsx:229 #: src/view/screens/CommunityGuidelines.tsx:32 msgid "Community Guidelines" msgstr "Diretrizes da Comunidade" @@ -786,7 +755,7 @@ msgstr "Completar e começar a usar sua conta" #: src/view/com/auth/create/Step3.tsx:73 msgid "Complete the challenge" -msgstr "" +msgstr "Complete o captcha" #: src/view/com/composer/Composer.tsx:424 msgid "Compose posts up to {MAX_GRAPHEME_LENGTH} characters in length" @@ -800,7 +769,7 @@ msgstr "Escrever resposta" msgid "Configure content filtering setting for category: {0}" msgstr "Configure o filtro de conteúdo por categoria: {0}" -#: src/components/Prompt.tsx:113 +#: src/components/Prompt.tsx:124 #: src/view/com/modals/AppealLabel.tsx:98 #: src/view/com/modals/SelfLabel.tsx:154 #: src/view/com/modals/VerifyEmail.tsx:231 @@ -840,8 +809,8 @@ msgid "Confirmation code" msgstr "Código de confirmação" #: src/view/com/modals/Waitlist.tsx:120 -msgid "Confirms signing up {email} to the waitlist" -msgstr "Confirma adição de {email} à lista de espera" +#~ msgid "Confirms signing up {email} to the waitlist" +#~ msgstr "Confirma adição de {email} à lista de espera" #: src/view/com/auth/create/CreateAccount.tsx:193 #: src/view/com/auth/login/LoginForm.tsx:278 @@ -918,7 +887,7 @@ msgstr "Versão do aplicativo copiada" #: src/view/com/modals/AddAppPasswords.tsx:76 #: src/view/com/modals/InviteCodes.tsx:152 -#: src/view/com/util/forms/PostDropdownBtn.tsx:143 +#: src/view/com/util/forms/PostDropdownBtn.tsx:161 msgid "Copied to clipboard" msgstr "Copiado" @@ -934,7 +903,8 @@ msgstr "Copiar" msgid "Copy link to list" msgstr "Copiar link da lista" -#: src/view/com/util/forms/PostDropdownBtn.tsx:184 +#: src/view/com/util/forms/PostDropdownBtn.tsx:231 +#: src/view/com/util/forms/PostDropdownBtn.tsx:237 msgid "Copy link to post" msgstr "Copiar link do post" @@ -942,11 +912,12 @@ msgstr "Copiar link do post" msgid "Copy link to profile" msgstr "Copiar link do perfil" -#: src/view/com/util/forms/PostDropdownBtn.tsx:170 +#: src/view/com/util/forms/PostDropdownBtn.tsx:223 +#: src/view/com/util/forms/PostDropdownBtn.tsx:225 msgid "Copy post text" msgstr "Copiar texto do post" -#: src/Navigation.tsx:232 +#: src/Navigation.tsx:234 #: src/view/screens/CopyrightPolicy.tsx:29 msgid "Copyright Policy" msgstr "PolÃtica de Direitos Autorais" @@ -955,14 +926,10 @@ msgstr "PolÃtica de Direitos Autorais" msgid "Could not load feed" msgstr "Não foi possÃvel carregar o feed" -#: src/view/screens/ProfileList.tsx:888 +#: src/view/screens/ProfileList.tsx:893 msgid "Could not load list" msgstr "Não foi possÃvel carregar a lista" -#: src/view/com/auth/create/Step2.tsx:91 -#~ msgid "Country" -#~ msgstr "PaÃs" - #: src/view/com/auth/HomeLoggedOutCTA.tsx:62 #: src/view/com/auth/SplashScreen.tsx:71 #: src/view/com/auth/SplashScreen.web.tsx:81 @@ -1009,7 +976,7 @@ msgstr "Cultura" #: src/view/com/auth/server-input/index.tsx:95 #: src/view/com/auth/server-input/index.tsx:96 msgid "Custom" -msgstr "" +msgstr "Customizado" #: src/view/com/modals/ChangeHandle.tsx:389 msgid "Custom domain" @@ -1024,10 +991,6 @@ msgstr "Feeds customizados feitos pela comunidade te proporcionam novas experiê msgid "Customize media from external sites." msgstr "Configurar mÃdia de sites externos." -#: src/view/screens/Settings.tsx:687 -#~ msgid "Danger Zone" -#~ msgstr "Zona Perigosa" - #: src/view/screens/Settings/index.tsx:485 #: src/view/screens/Settings/index.tsx:511 msgid "Dark" @@ -1067,19 +1030,16 @@ msgstr "Excluir Lista" msgid "Delete my account" msgstr "Excluir minha conta" -#: src/view/screens/Settings.tsx:706 -#~ msgid "Delete my account…" -#~ msgstr "Excluir minha conta…" - #: src/view/screens/Settings/index.tsx:784 msgid "Delete My Account…" msgstr "Excluir minha conta…" -#: src/view/com/util/forms/PostDropdownBtn.tsx:273 +#: src/view/com/util/forms/PostDropdownBtn.tsx:317 +#: src/view/com/util/forms/PostDropdownBtn.tsx:326 msgid "Delete post" msgstr "Excluir post" -#: src/view/com/util/forms/PostDropdownBtn.tsx:277 +#: src/view/com/util/forms/PostDropdownBtn.tsx:321 msgid "Delete this post?" msgstr "Excluir este post?" @@ -1127,13 +1087,9 @@ msgstr "Desencorajar aplicativos a mostrar minha conta para usuários deslogados msgid "Discover new custom feeds" msgstr "Descubra novos feeds" -#: src/view/screens/Feeds.tsx:473 -#~ msgid "Discover new feeds" -#~ msgstr "Descubra novos feeds" - #: src/view/screens/Feeds.tsx:689 msgid "Discover New Feeds" -msgstr "" +msgstr "Descubra Novos Feeds" #: src/view/com/modals/EditProfile.tsx:192 msgid "Display name" @@ -1148,8 +1104,8 @@ msgid "Domain verified!" msgstr "DomÃnio verificado!" #: src/view/com/auth/create/Step1.tsx:170 -msgid "Don't have an invite code?" -msgstr "Não possui um convite?" +#~ msgid "Don't have an invite code?" +#~ msgstr "Não possui um convite?" #: src/view/com/auth/onboarding/RecommendedFollows.tsx:86 #: src/view/com/modals/EditImage.tsx:333 @@ -1190,12 +1146,12 @@ msgstr "Toque duas vezes para logar" #: src/view/screens/Settings/index.tsx:755 msgid "Download Bluesky account data (repository)" -msgstr "" +msgstr "Baixar os dados da minha conta Bluesky (repositório)" #: src/view/screens/Settings/ExportCarDialog.tsx:59 #: src/view/screens/Settings/ExportCarDialog.tsx:63 msgid "Download CAR file" -msgstr "" +msgstr "Baixar arquivo CAR" #: src/view/com/composer/text-input/TextInput.web.tsx:249 msgid "Drop to add images" @@ -1251,7 +1207,7 @@ msgstr "Editar detalhes da lista" msgid "Edit Moderation List" msgstr "Editar lista de moderação" -#: src/Navigation.tsx:242 +#: src/Navigation.tsx:244 #: src/view/screens/Feeds.tsx:434 #: src/view/screens/SavedFeeds.tsx:84 msgid "Edit My Feeds" @@ -1269,7 +1225,7 @@ msgstr "Editar perfil" msgid "Edit Profile" msgstr "Editar Perfil" -#: src/view/com/home/HomeHeaderLayout.web.tsx:59 +#: src/view/com/home/HomeHeaderLayout.web.tsx:62 #: src/view/screens/Feeds.tsx:355 msgid "Edit Saved Feeds" msgstr "Editar Feeds Salvos" @@ -1290,14 +1246,13 @@ msgstr "Editar sua descrição" msgid "Education" msgstr "Educação" -#: src/view/com/auth/create/Step1.tsx:199 +#: src/view/com/auth/create/Step1.tsx:176 #: src/view/com/auth/login/ForgotPasswordForm.tsx:156 #: src/view/com/modals/ChangeEmail.tsx:141 -#: src/view/com/modals/Waitlist.tsx:88 msgid "Email" msgstr "E-mail" -#: src/view/com/auth/create/Step1.tsx:190 +#: src/view/com/auth/create/Step1.tsx:167 #: src/view/com/auth/login/ForgotPasswordForm.tsx:147 msgid "Email address" msgstr "Endereço de e-mail" @@ -1352,10 +1307,10 @@ msgstr "Fim do feed" msgid "Enter a name for this App Password" msgstr "Insira um nome para esta Senha de Aplicativo" -#: src/components/dialogs/MutedWords.tsx:87 -#: src/components/dialogs/MutedWords.tsx:88 +#: src/components/dialogs/MutedWords.tsx:100 +#: src/components/dialogs/MutedWords.tsx:101 msgid "Enter a word or tag" -msgstr "" +msgstr "Digite uma palavra ou tag" #: src/view/com/modals/VerifyEmail.tsx:105 msgid "Enter Confirmation Code" @@ -1373,16 +1328,16 @@ msgstr "Digite o domÃnio que você deseja usar" msgid "Enter the email you used to create your account. We'll send you a \"reset code\" so you can set a new password." msgstr "Digite o e-mail que você usou para criar a sua conta. Nós lhe enviaremos um \"código de redefinição\" para que você possa definir uma nova senha." -#: src/view/com/auth/create/Step1.tsx:251 +#: src/view/com/auth/create/Step1.tsx:228 #: src/view/com/modals/BirthDateSettings.tsx:74 msgid "Enter your birth date" msgstr "Insira seu aniversário" #: src/view/com/modals/Waitlist.tsx:78 -msgid "Enter your email" -msgstr "Digite seu e-mail" +#~ msgid "Enter your email" +#~ msgstr "Digite seu e-mail" -#: src/view/com/auth/create/Step1.tsx:195 +#: src/view/com/auth/create/Step1.tsx:172 msgid "Enter your email address" msgstr "Digite seu endereço de e-mail" @@ -1394,17 +1349,13 @@ msgstr "Digite o novo e-mail acima" msgid "Enter your new email address below." msgstr "Digite seu novo endereço de e-mail abaixo." -#: src/view/com/auth/create/Step2.tsx:188 -#~ msgid "Enter your phone number" -#~ msgstr "Digite seu número de telefone" - #: src/view/com/auth/login/Login.tsx:99 msgid "Enter your username and password" msgstr "Digite seu nome de usuário e senha" #: src/view/com/auth/create/Step3.tsx:67 msgid "Error receiving captcha response." -msgstr "" +msgstr "Não foi possÃvel processar o captcha." #: src/view/screens/Search/Search.tsx:110 msgid "Error:" @@ -1428,8 +1379,8 @@ msgid "Exits inputting search query" msgstr "Sair da busca" #: src/view/com/modals/Waitlist.tsx:138 -msgid "Exits signing up for waitlist with {email}" -msgstr "Desistir de entrar na lista de espera" +#~ msgid "Exits signing up for waitlist with {email}" +#~ msgstr "Desistir de entrar na lista de espera" #: src/view/com/lightbox/Lightbox.web.tsx:163 msgid "Expand alt text" @@ -1442,12 +1393,12 @@ msgstr "Mostrar ou esconder o post a que você está respondendo" #: src/view/screens/Settings/index.tsx:753 msgid "Export my data" -msgstr "" +msgstr "Exportar meus dados" #: src/view/screens/Settings/ExportCarDialog.tsx:44 #: src/view/screens/Settings/index.tsx:764 msgid "Export My Data" -msgstr "" +msgstr "Exportar Meus Dados" #: src/view/com/modals/EmbedConsent.tsx:64 msgid "External Media" @@ -1458,7 +1409,7 @@ msgstr "MÃdia Externa" msgid "External media may allow websites to collect information about you and your device. No information is sent or requested until you press the \"play\" button." msgstr "MÃdias externas podem permitir que sites coletem informações sobre você e seu dispositivo. Nenhuma informação é enviada ou solicitada até que você pressione o botão de \"play\"." -#: src/Navigation.tsx:261 +#: src/Navigation.tsx:263 #: src/view/screens/PreferencesExternalEmbeds.tsx:52 #: src/view/screens/Settings/index.tsx:657 msgid "External Media Preferences" @@ -1477,7 +1428,7 @@ msgstr "Não foi possÃvel criar senha de aplicativo." msgid "Failed to create the list. Check your internet connection and try again." msgstr "Não foi possÃvel criar a lista. Por favor tente novamente." -#: src/view/com/util/forms/PostDropdownBtn.tsx:110 +#: src/view/com/util/forms/PostDropdownBtn.tsx:128 msgid "Failed to delete post, please try again" msgstr "Não foi possÃvel excluir o post, por favor tente novamente." @@ -1486,7 +1437,7 @@ msgstr "Não foi possÃvel excluir o post, por favor tente novamente." msgid "Failed to load recommended feeds" msgstr "Falha ao carregar feeds recomendados" -#: src/Navigation.tsx:192 +#: src/Navigation.tsx:194 msgid "Feed" msgstr "Feed" @@ -1507,7 +1458,7 @@ msgstr "Feed offline" msgid "Feedback" msgstr "Comentários" -#: src/Navigation.tsx:445 +#: src/Navigation.tsx:452 #: src/view/screens/Feeds.tsx:419 #: src/view/screens/Feeds.tsx:524 #: src/view/screens/Profile.tsx:184 @@ -1518,14 +1469,6 @@ msgstr "Comentários" msgid "Feeds" msgstr "Feeds" -#: src/screens/Onboarding/StepAlgoFeeds/index.tsx:106 -#~ msgid "Feeds are created by users and can give you entirely new experiences." -#~ msgstr "Feeds são criados por usuários e podem te dar experiências completamente únicas." - -#: src/screens/Onboarding/StepAlgoFeeds/index.tsx:106 -#~ msgid "Feeds are created by users and organizations. They offer you varied experiences and suggest content you may like using algorithms." -#~ msgstr "Feeds são criados por usuários ou organizações. Eles oferecem experiências únicas e podem te sugerir conteúdo usando algoritmos próprios." - #: src/view/com/auth/onboarding/RecommendedFeeds.tsx:57 msgid "Feeds are created by users to curate content. Choose some feeds that you find interesting." msgstr "Os feeds são criados por usuários para curadoria de conteúdo. Escolha alguns feeds que você acha interessantes." @@ -1562,11 +1505,7 @@ msgstr "Procurando contas semelhantes..." #: src/view/screens/PreferencesFollowingFeed.tsx:111 msgid "Fine-tune the content you see on your Following feed." -msgstr "" - -#: src/view/screens/PreferencesHomeFeed.tsx:111 -#~ msgid "Fine-tune the content you see on your home screen." -#~ msgstr "Ajuste o conteúdo que você vê na sua tela inicial." +msgstr "Ajuste o conteúdo que você vê na sua tela inicial." #: src/view/screens/PreferencesThreads.tsx:60 msgid "Fine-tune the discussion threads." @@ -1648,13 +1587,13 @@ msgstr "Seguindo" msgid "Following {0}" msgstr "Seguindo {0}" -#: src/Navigation.tsx:248 -#: src/view/com/home/HomeHeaderLayout.web.tsx:45 -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:83 +#: src/Navigation.tsx:250 +#: src/view/com/home/HomeHeaderLayout.web.tsx:50 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:84 #: src/view/screens/PreferencesFollowingFeed.tsx:104 #: src/view/screens/Settings/index.tsx:543 msgid "Following Feed Preferences" -msgstr "" +msgstr "Configurações do feed principal" #: src/view/com/profile/ProfileHeader.tsx:546 msgid "Follows you" @@ -1689,6 +1628,11 @@ msgstr "Esqueci a senha" msgid "Forgot Password" msgstr "Esqueci a Senha" +#: src/screens/Hashtag.tsx:108 +#: src/screens/Hashtag.tsx:148 +msgid "From @{sanitizedAuthor}" +msgstr "De @{sanitizedAuthor}" + #: src/view/com/posts/FeedItem.tsx:189 msgctxt "from-feed" msgid "From <0/>" @@ -1712,8 +1656,8 @@ msgstr "Voltar" #: src/view/screens/ProfileFeed.tsx:106 #: src/view/screens/ProfileFeed.tsx:111 -#: src/view/screens/ProfileList.tsx:897 #: src/view/screens/ProfileList.tsx:902 +#: src/view/screens/ProfileList.tsx:907 msgid "Go Back" msgstr "Voltar" @@ -1739,9 +1683,17 @@ msgstr "Próximo" msgid "Handle" msgstr "Usuário" +#: src/Navigation.tsx:270 +msgid "Hashtag" +msgstr "Hashtag" + #: src/components/RichText.tsx:188 -msgid "Hashtag: {tag}" -msgstr "" +#~ msgid "Hashtag: {tag}" +#~ msgstr "Hashtag: {tag}" + +#: src/components/RichText.tsx:190 +msgid "Hashtag: #{tag}" +msgstr "Hashtag: #{tag}" #: src/view/com/auth/create/CreateAccount.tsx:208 msgid "Having trouble?" @@ -1776,12 +1728,13 @@ msgid "Hide" msgstr "Ocultar" #: src/view/com/modals/ContentFilteringSettings.tsx:224 -#: src/view/com/notifications/FeedItem.tsx:325 +#: src/view/com/notifications/FeedItem.tsx:326 msgctxt "action" msgid "Hide" msgstr "Esconder" -#: src/view/com/util/forms/PostDropdownBtn.tsx:232 +#: src/view/com/util/forms/PostDropdownBtn.tsx:276 +#: src/view/com/util/forms/PostDropdownBtn.tsx:287 msgid "Hide post" msgstr "Ocultar post" @@ -1790,11 +1743,11 @@ msgstr "Ocultar post" msgid "Hide the content" msgstr "Esconder o conteúdo" -#: src/view/com/util/forms/PostDropdownBtn.tsx:236 +#: src/view/com/util/forms/PostDropdownBtn.tsx:280 msgid "Hide this post?" msgstr "Ocultar este post?" -#: src/view/com/notifications/FeedItem.tsx:315 +#: src/view/com/notifications/FeedItem.tsx:316 msgid "Hide user list" msgstr "Ocultar lista de usuários" @@ -1822,7 +1775,7 @@ msgstr "Hmm, o servidor do feed teve algum problema. Por favor, avise o criador msgid "Hmm, we're having trouble finding this feed. It may have been deleted." msgstr "Hmm, estamos com problemas para encontrar este feed. Ele pode ter sido excluÃdo." -#: src/Navigation.tsx:435 +#: src/Navigation.tsx:442 #: src/view/shell/bottom-bar/BottomBar.tsx:137 #: src/view/shell/desktop/LeftNav.tsx:306 #: src/view/shell/Drawer.tsx:398 @@ -1837,7 +1790,7 @@ msgstr "Página Inicial" #~ msgid "Home Feed Preferences" #~ msgstr "Preferências da Página Inicial" -#: src/view/com/auth/create/Step1.tsx:82 +#: src/view/com/auth/create/Step1.tsx:75 #: src/view/com/auth/login/ForgotPasswordForm.tsx:120 msgid "Hosting provider" msgstr "Provedor de hospedagem" @@ -1891,11 +1844,11 @@ msgstr "Insira o código enviado para o seu e-mail para redefinir sua senha" msgid "Input confirmation code for account deletion" msgstr "Insira o código de confirmação para excluir sua conta" -#: src/view/com/auth/create/Step1.tsx:200 +#: src/view/com/auth/create/Step1.tsx:177 msgid "Input email for Bluesky account" msgstr "Insira o e-mail para a sua conta do Bluesky" -#: src/view/com/auth/create/Step1.tsx:158 +#: src/view/com/auth/create/Step1.tsx:151 msgid "Input invite code to proceed" msgstr "Insira o convite para continuar" @@ -1911,10 +1864,6 @@ msgstr "Insira a nova senha" msgid "Input password for account deletion" msgstr "Insira a senha para excluir a conta" -#: src/view/com/auth/create/Step2.tsx:196 -#~ msgid "Input phone number for SMS verification" -#~ msgstr "Insira o número de telefone para verificação via SMS" - #: src/view/com/auth/login/LoginForm.tsx:230 msgid "Input the password tied to {identifier}" msgstr "Insira a senha da conta {identifier}" @@ -1923,13 +1872,9 @@ msgstr "Insira a senha da conta {identifier}" msgid "Input the username or email address you used at signup" msgstr "Insira o usuário ou e-mail que você cadastrou" -#: src/view/com/auth/create/Step2.tsx:271 -#~ msgid "Input the verification code we have texted to you" -#~ msgstr "Insira o código de verificação que enviamos para você" - #: src/view/com/modals/Waitlist.tsx:90 -msgid "Input your email to get on the Bluesky waitlist" -msgstr "Insira seu e-mail para entrar na lista de espera do Bluesky" +#~ msgid "Input your email to get on the Bluesky waitlist" +#~ msgstr "Insira seu e-mail para entrar na lista de espera do Bluesky" #: src/view/com/auth/login/LoginForm.tsx:229 msgid "Input your password" @@ -1947,16 +1892,12 @@ msgstr "Post inválido" msgid "Invalid username or password" msgstr "Credenciais inválidas" -#: src/view/screens/Settings.tsx:411 -#~ msgid "Invite" -#~ msgstr "Convidar" - #: src/view/com/modals/InviteCodes.tsx:93 msgid "Invite a Friend" msgstr "Convide um Amigo" -#: src/view/com/auth/create/Step1.tsx:148 -#: src/view/com/auth/create/Step1.tsx:157 +#: src/view/com/auth/create/Step1.tsx:141 +#: src/view/com/auth/create/Step1.tsx:150 msgid "Invite code" msgstr "Convite" @@ -1968,10 +1909,6 @@ msgstr "Convite inválido. Verifique se você o inseriu corretamente e tente nov msgid "Invite codes: {0} available" msgstr "Convites: {0} disponÃveis" -#: src/view/shell/Drawer.tsx:645 -#~ msgid "Invite codes: {invitesAvailable} available" -#~ msgstr "Convites: {invitesAvailable} disponÃvel" - #: src/view/com/modals/InviteCodes.tsx:169 msgid "Invite codes: 1 available" msgstr "Convites: 1 disponÃvel" @@ -1986,17 +1923,17 @@ msgid "Jobs" msgstr "Carreiras" #: src/view/com/modals/Waitlist.tsx:67 -msgid "Join the waitlist" -msgstr "Junte-se à lista de espera" +#~ msgid "Join the waitlist" +#~ msgstr "Junte-se à lista de espera" #: src/view/com/auth/create/Step1.tsx:174 #: src/view/com/auth/create/Step1.tsx:178 -msgid "Join the waitlist." -msgstr "Junte-se à lista de espera." +#~ msgid "Join the waitlist." +#~ msgstr "Junte-se à lista de espera." #: src/view/com/modals/Waitlist.tsx:128 -msgid "Join Waitlist" -msgstr "Junte-se à Lista de Espera" +#~ msgid "Join Waitlist" +#~ msgstr "Junte-se à Lista de Espera" #: src/screens/Onboarding/index.tsx:24 msgid "Journalism" @@ -2010,7 +1947,7 @@ msgstr "Seleção de idioma" msgid "Language settings" msgstr "Configuração de Idioma" -#: src/Navigation.tsx:140 +#: src/Navigation.tsx:142 #: src/view/screens/LanguageSettings.tsx:89 msgid "Language Settings" msgstr "Configurações de Idiomas" @@ -2080,7 +2017,6 @@ msgid "Light" msgstr "Claro" #: src/view/com/util/post-ctrls/PostCtrls.tsx:182 -#: src/view/com/util/post-ctrls/PostCtrls.tsx:216 msgid "Like" msgstr "Curtir" @@ -2088,7 +2024,7 @@ msgstr "Curtir" msgid "Like this feed" msgstr "Curtir este feed" -#: src/Navigation.tsx:197 +#: src/Navigation.tsx:199 msgid "Liked by" msgstr "Curtido por" @@ -2121,7 +2057,7 @@ msgstr "Curtidas" msgid "Likes on this post" msgstr "Curtidas neste post" -#: src/Navigation.tsx:166 +#: src/Navigation.tsx:168 msgid "List" msgstr "Lista" @@ -2157,7 +2093,7 @@ msgstr "Lista desbloqueada" msgid "List unmuted" msgstr "Lista dessilenciada" -#: src/Navigation.tsx:110 +#: src/Navigation.tsx:112 #: src/view/screens/Profile.tsx:185 #: src/view/shell/desktop/LeftNav.tsx:379 #: src/view/shell/Drawer.tsx:492 @@ -2189,7 +2125,7 @@ msgstr "Carregando..." #~ msgid "Local dev server" #~ msgstr "Servidor de desenvolvimento local" -#: src/Navigation.tsx:207 +#: src/Navigation.tsx:209 msgid "Log" msgstr "Registros" @@ -2212,17 +2148,17 @@ msgstr "Fazer login em uma conta que não está listada" msgid "Make sure this is where you intend to go!" msgstr "Certifique-se de onde está indo!" -#: src/components/dialogs/MutedWords.tsx:71 +#: src/components/dialogs/MutedWords.tsx:83 msgid "Manage your muted words and tags" -msgstr "" +msgstr "Gerencie suas palavras/tags silenciadas" #: src/view/com/auth/create/Step2.tsx:118 msgid "May not be longer than 253 characters" -msgstr "" +msgstr "Não pode ter mais que 253 caracteres" #: src/view/com/auth/create/Step2.tsx:109 msgid "May only contain letters and numbers" -msgstr "" +msgstr "Só pode conter letras e números" #: src/view/screens/Profile.tsx:182 msgid "Media" @@ -2236,7 +2172,7 @@ msgstr "usuários mencionados" msgid "Mentioned users" msgstr "Usuários mencionados" -#: src/view/com/util/ViewHeader.tsx:81 +#: src/view/com/util/ViewHeader.tsx:87 #: src/view/screens/Search/Search.tsx:646 msgid "Menu" msgstr "Menu" @@ -2245,7 +2181,7 @@ msgstr "Menu" msgid "Message from server: {0}" msgstr "Mensagem do servidor: {0}" -#: src/Navigation.tsx:115 +#: src/Navigation.tsx:117 #: src/view/screens/Moderation.tsx:66 #: src/view/screens/Settings/index.tsx:625 #: src/view/shell/desktop/LeftNav.tsx:397 @@ -2259,13 +2195,13 @@ msgstr "Moderação" msgid "Moderation list by {0}" msgstr "Lista de moderação por {0}" -#: src/view/screens/ProfileList.tsx:774 +#: src/view/screens/ProfileList.tsx:775 msgid "Moderation list by <0/>" msgstr "Lista de moderação por <0/>" #: src/view/com/lists/ListCard.tsx:91 #: src/view/com/modals/UserAddRemoveLists.tsx:204 -#: src/view/screens/ProfileList.tsx:772 +#: src/view/screens/ProfileList.tsx:773 msgid "Moderation list by you" msgstr "Lista de moderação por você" @@ -2281,7 +2217,7 @@ msgstr "Lista de moderação criada" msgid "Moderation lists" msgstr "Listas de moderação" -#: src/Navigation.tsx:120 +#: src/Navigation.tsx:122 #: src/view/screens/ModerationModlists.tsx:58 msgid "Moderation Lists" msgstr "Listas de Moderação" @@ -2294,7 +2230,7 @@ msgstr "Moderação" msgid "Moderator has chosen to set a general warning on the content." msgstr "O moderador escolheu um aviso geral neste conteúdo." -#: src/view/shell/desktop/Feeds.tsx:63 +#: src/view/shell/desktop/Feeds.tsx:65 msgid "More feeds" msgstr "Mais feeds" @@ -2305,8 +2241,8 @@ msgid "More options" msgstr "Mais opções" #: src/view/com/util/forms/PostDropdownBtn.tsx:315 -msgid "More post options" -msgstr "Mais opções do post" +#~ msgid "More post options" +#~ msgstr "Mais opções do post" #: src/view/screens/PreferencesThreads.tsx:82 msgid "Most-liked replies first" @@ -2314,15 +2250,15 @@ msgstr "Respostas mais curtidas primeiro" #: src/view/com/auth/create/Step2.tsx:122 msgid "Must be at least 3 characters" -msgstr "" +msgstr "Deve ter no mÃnimo 3 caracteres" -#: src/components/TagMenu/index.tsx:253 +#: src/components/TagMenu/index.tsx:249 msgid "Mute" -msgstr "" +msgstr "Silenciar" -#: src/components/TagMenu/index.web.tsx:91 +#: src/components/TagMenu/index.web.tsx:105 msgid "Mute {truncatedTag}" -msgstr "" +msgstr "Silenciar {truncatedTag}" #: src/view/com/profile/ProfileHeader.tsx:327 msgid "Mute Account" @@ -2332,17 +2268,21 @@ msgstr "Silenciar Conta" msgid "Mute accounts" msgstr "Silenciar contas" +#: src/components/TagMenu/index.tsx:209 +msgid "Mute all {displayTag} posts" +msgstr "Silenciar posts com {displayTag}" + #: src/components/TagMenu/index.tsx:211 -msgid "Mute all {tag} posts" -msgstr "" +#~ msgid "Mute all {tag} posts" +#~ msgstr "Silenciar posts com {tag}" -#: src/components/dialogs/MutedWords.tsx:131 +#: src/components/dialogs/MutedWords.tsx:149 msgid "Mute in tags only" -msgstr "" +msgstr "Silenciar apenas as tags" -#: src/components/dialogs/MutedWords.tsx:116 +#: src/components/dialogs/MutedWords.tsx:134 msgid "Mute in text & tags" -msgstr "" +msgstr "Silenciar texto e tags" #: src/view/screens/ProfileList.tsx:491 msgid "Mute list" @@ -2356,21 +2296,23 @@ msgstr "Silenciar estas contas?" msgid "Mute this List" msgstr "Silenciar esta lista" -#: src/components/dialogs/MutedWords.tsx:109 +#: src/components/dialogs/MutedWords.tsx:127 msgid "Mute this word in post text and tags" -msgstr "" +msgstr "Silenciar esta palavra no conteúdo de um post e tags" -#: src/components/dialogs/MutedWords.tsx:124 +#: src/components/dialogs/MutedWords.tsx:142 msgid "Mute this word in tags only" -msgstr "" +msgstr "Silenciar esta palavra apenas nas tags de um post" -#: src/view/com/util/forms/PostDropdownBtn.tsx:202 +#: src/view/com/util/forms/PostDropdownBtn.tsx:251 +#: src/view/com/util/forms/PostDropdownBtn.tsx:257 msgid "Mute thread" msgstr "Silenciar thread" -#: src/view/com/util/forms/PostDropdownBtn.tsx:216 +#: src/view/com/util/forms/PostDropdownBtn.tsx:267 +#: src/view/com/util/forms/PostDropdownBtn.tsx:269 msgid "Mute words & tags" -msgstr "" +msgstr "Silenciar palavras/tags" #: src/view/com/lists/ListCard.tsx:102 msgid "Muted" @@ -2380,7 +2322,7 @@ msgstr "Silenciada" msgid "Muted accounts" msgstr "Contas silenciadas" -#: src/Navigation.tsx:125 +#: src/Navigation.tsx:127 #: src/view/screens/ModerationMutedAccounts.tsx:107 msgid "Muted Accounts" msgstr "Contas Silenciadas" @@ -2391,7 +2333,7 @@ msgstr "Contas silenciadas não aparecem no seu feed ou nas suas notificações. #: src/view/screens/Moderation.tsx:100 msgid "Muted words & tags" -msgstr "" +msgstr "Palavras/tags silenciadas" #: src/view/screens/ProfileList.tsx:277 msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them." @@ -2415,7 +2357,7 @@ msgstr "Meus Feeds Salvos" #: src/view/com/auth/server-input/index.tsx:118 msgid "my-server.com" -msgstr "" +msgstr "meu-servidor.com.br" #: src/view/com/modals/AddAppPasswords.tsx:179 #: src/view/com/modals/CreateOrEditList.tsx:290 @@ -2456,9 +2398,9 @@ msgstr "Nunca perca o acesso aos seus seguidores e dados." msgid "Never lose access to your followers or data." msgstr "Nunca perca o acesso aos seus seguidores ou dados." -#: src/components/dialogs/MutedWords.tsx:244 +#: src/components/dialogs/MutedWords.tsx:293 msgid "Nevermind" -msgstr "" +msgstr "Deixa pra lá" #: src/view/screens/Lists.tsx:76 msgctxt "action" @@ -2544,7 +2486,7 @@ msgid "No" msgstr "Não" #: src/view/screens/ProfileFeed.tsx:584 -#: src/view/screens/ProfileList.tsx:754 +#: src/view/screens/ProfileList.tsx:755 msgid "No description" msgstr "Sem descrição" @@ -2561,6 +2503,10 @@ msgstr "Nenhuma notificação!" msgid "No result" msgstr "Nenhum resultado" +#: src/components/Lists.tsx:192 +msgid "No results found" +msgstr "Nenhum resultado encontrado" + #: src/view/screens/Feeds.tsx:495 msgid "No results found for \"{query}\"" msgstr "Nenhum resultado encontrado para \"{query}\"" @@ -2583,7 +2529,7 @@ msgstr "Ninguém" msgid "Not Applicable." msgstr "Não Aplicável." -#: src/Navigation.tsx:105 +#: src/Navigation.tsx:107 #: src/view/screens/Profile.tsx:106 msgid "Not Found" msgstr "Não encontrado" @@ -2597,7 +2543,7 @@ msgstr "Agora não" msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites." msgstr "Nota: o Bluesky é uma rede aberta e pública. Esta configuração limita somente a visibilidade do seu conteúdo no site e aplicativo do Bluesky, e outros aplicativos podem não respeitar esta configuração. Seu conteúdo ainda poderá ser exibido para usuários deslogados por outros aplicativos e sites." -#: src/Navigation.tsx:450 +#: src/Navigation.tsx:457 #: src/view/screens/Notifications.tsx:124 #: src/view/screens/Notifications.tsx:148 #: src/view/shell/bottom-bar/BottomBar.tsx:205 @@ -2639,6 +2585,11 @@ msgstr "Uma ou mais imagens estão sem texto alternativo." msgid "Only {0} can reply." msgstr "Apenas {0} pode responder." +#: src/components/Lists.tsx:82 +msgid "Oops, something went wrong!" +msgstr "Opa, algo deu errado!" + +#: src/components/Lists.tsx:188 #: src/view/screens/AppPasswords.tsx:65 #: src/view/screens/Profile.tsx:106 msgid "Oops!" @@ -2650,7 +2601,7 @@ msgstr "Abrir" #: src/view/screens/Moderation.tsx:75 msgid "Open content filtering settings" -msgstr "" +msgstr "Abrir configurações de filtro" #: src/view/com/composer/Composer.tsx:477 #: src/view/com/composer/Composer.tsx:478 @@ -2663,12 +2614,16 @@ msgstr "Abrir links no navegador interno" #: src/view/screens/Moderation.tsx:92 msgid "Open muted words settings" -msgstr "" +msgstr "Abrir configurações das palavras silenciadas" -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:49 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:50 msgid "Open navigation" msgstr "Abrir navegação" +#: src/view/com/util/forms/PostDropdownBtn.tsx:175 +msgid "Open post options menu" +msgstr "Abrir opções do post" + #: src/view/screens/Settings/index.tsx:804 msgid "Open storybook page" msgstr "Abre o storybook" @@ -2681,7 +2636,7 @@ msgstr "Abre {numItems} opções" msgid "Opens additional details for a debug entry" msgstr "Abre detalhes adicionais para um registro de depuração" -#: src/view/com/notifications/FeedItem.tsx:348 +#: src/view/com/notifications/FeedItem.tsx:349 msgid "Opens an expanded list of users in this notification" msgstr "Abre a lista de usuários nesta notificação" @@ -2717,10 +2672,6 @@ msgstr "Abre lista de seguidores" msgid "Opens following list" msgstr "Abre lista de seguidos" -#: src/view/screens/Settings.tsx:412 -#~ msgid "Opens invite code list" -#~ msgstr "Abre lista de convites" - #: src/view/com/modals/InviteCodes.tsx:172 msgid "Opens list of invite codes" msgstr "Abre a lista de códigos de convite" @@ -2741,7 +2692,7 @@ msgstr "Abre configurações de moderação" msgid "Opens password reset form" msgstr "Abre o formulário de redefinição de senha" -#: src/view/com/home/HomeHeaderLayout.web.tsx:60 +#: src/view/com/home/HomeHeaderLayout.web.tsx:63 #: src/view/screens/Feeds.tsx:356 msgid "Opens screen to edit Saved Feeds" msgstr "Abre a tela para editar feeds salvos" @@ -2782,14 +2733,11 @@ msgstr "Ou combine estas opções:" msgid "Other account" msgstr "Outra conta" -#: src/view/com/modals/ServerInput.tsx:88 -#~ msgid "Other service" -#~ msgstr "Outro serviço" - #: src/view/com/composer/select-language/SelectLangBtn.tsx:91 msgid "Other..." msgstr "Outro..." +#: src/components/Lists.tsx:194 #: src/view/screens/NotFound.tsx:45 msgid "Page not found" msgstr "Página não encontrada" @@ -2798,8 +2746,8 @@ msgstr "Página não encontrada" msgid "Page Not Found" msgstr "Página Não Encontrada" -#: src/view/com/auth/create/Step1.tsx:214 -#: src/view/com/auth/create/Step1.tsx:224 +#: src/view/com/auth/create/Step1.tsx:191 +#: src/view/com/auth/create/Step1.tsx:201 #: src/view/com/auth/login/LoginForm.tsx:226 #: src/view/com/auth/login/SetNewPasswordForm.tsx:161 #: src/view/com/modals/DeleteAccount.tsx:202 @@ -2814,11 +2762,11 @@ msgstr "Senha atualizada" msgid "Password updated!" msgstr "Senha atualizada!" -#: src/Navigation.tsx:160 +#: src/Navigation.tsx:162 msgid "People followed by @{0}" msgstr "Pessoas seguidas por @{0}" -#: src/Navigation.tsx:153 +#: src/Navigation.tsx:155 msgid "People following @{0}" msgstr "Pessoas seguindo @{0}" @@ -2834,10 +2782,6 @@ msgstr "A permissão de galeria foi recusada. Por favor, habilite-a nas configur msgid "Pets" msgstr "Pets" -#: src/view/com/auth/create/Step2.tsx:183 -#~ msgid "Phone number" -#~ msgstr "Número de telefone" - #: src/view/com/modals/SelfLabel.tsx:121 msgid "Pictures meant for adults." msgstr "Imagens destinadas a adultos." @@ -2874,7 +2818,7 @@ msgstr "Por favor, escolha sua senha." #: src/view/com/auth/create/state.ts:131 msgid "Please complete the verification captcha." -msgstr "" +msgstr "Por favor, complete o captcha de verificação." #: src/view/com/modals/ChangeEmail.tsx:67 msgid "Please confirm your email before changing it. This is a temporary requirement while email-updating tools are added, and it will soon be removed." @@ -2884,14 +2828,14 @@ msgstr "Por favor, confirme seu e-mail antes de alterá-lo. Este é um requisito msgid "Please enter a name for your app password. All spaces is not allowed." msgstr "Por favor, insira um nome para a sua Senha de Aplicativo." -#: src/view/com/auth/create/Step2.tsx:206 -#~ msgid "Please enter a phone number that can receive SMS text messages." -#~ msgstr "Por favor, insira um número de telefone que possa receber mensagens SMS." - #: src/view/com/modals/AddAppPasswords.tsx:145 msgid "Please enter a unique name for this App Password or use our randomly generated one." msgstr "Por favor, insira um nome único para esta Senha de Aplicativo ou use nosso nome gerado automaticamente." +#: src/components/dialogs/MutedWords.tsx:68 +msgid "Please enter a valid word, tag, or phrase to mute" +msgstr "Por favor, insira uma palavra, tag ou frase para silenciar" + #: src/view/com/auth/create/state.ts:170 #~ msgid "Please enter the code you received by SMS." #~ msgstr "Por favor, digite o código recebido via SMS." @@ -2913,11 +2857,6 @@ msgstr "Por favor, digite sua senha também:" msgid "Please tell us why you think this content warning was incorrectly applied!" msgstr "Por favor, diga-nos por que você acha que este aviso de conteúdo foi aplicado incorretamente!" -#: src/view/com/modals/AppealLabel.tsx:72 -#: src/view/com/modals/AppealLabel.tsx:75 -#~ msgid "Please tell us why you think this decision was incorrect." -#~ msgstr "Por favor, conte-nos por que achou que esta decisão está incorreta." - #: src/view/com/modals/VerifyEmail.tsx:101 msgid "Please Verify Your Email" msgstr "Por favor, verifique seu e-mail" @@ -2949,13 +2888,13 @@ msgstr "Post" msgid "Post by {0}" msgstr "Post por {0}" -#: src/Navigation.tsx:172 -#: src/Navigation.tsx:179 -#: src/Navigation.tsx:186 +#: src/Navigation.tsx:174 +#: src/Navigation.tsx:181 +#: src/Navigation.tsx:188 msgid "Post by @{0}" msgstr "Post por @{0}" -#: src/view/com/util/forms/PostDropdownBtn.tsx:90 +#: src/view/com/util/forms/PostDropdownBtn.tsx:108 msgid "Post deleted" msgstr "Post excluÃdo" @@ -2975,17 +2914,17 @@ msgstr "Idiomas do Post" msgid "Post not found" msgstr "Post não encontrado" -#: src/components/TagMenu/index.tsx:257 +#: src/components/TagMenu/index.tsx:253 msgid "posts" -msgstr "" +msgstr "posts" #: src/view/screens/Profile.tsx:180 msgid "Posts" msgstr "Posts" -#: src/components/dialogs/MutedWords.tsx:77 +#: src/components/dialogs/MutedWords.tsx:90 msgid "Posts can be muted based on their text, their tags, or both." -msgstr "" +msgstr "Posts podem ser silenciados baseados no seu conteúdo, tags ou ambos." #: src/view/com/posts/FeedErrorMessage.tsx:64 msgid "Posts hidden" @@ -3012,7 +2951,7 @@ msgstr "Priorizar seus Seguidores" msgid "Privacy" msgstr "Privacidade" -#: src/Navigation.tsx:217 +#: src/Navigation.tsx:219 #: src/view/screens/PrivacyPolicy.tsx:29 #: src/view/screens/Settings/index.tsx:891 #: src/view/shell/Drawer.tsx:262 @@ -3089,7 +3028,7 @@ msgstr "Feeds Recomendados" msgid "Recommended Users" msgstr "Usuários Recomendados" -#: src/components/dialogs/MutedWords.tsx:249 +#: src/components/dialogs/MutedWords.tsx:298 #: src/view/com/modals/ListAddRemoveUsers.tsx:264 #: src/view/com/modals/SelfLabel.tsx:83 #: src/view/com/modals/UserAddRemoveLists.tsx:219 @@ -3127,9 +3066,9 @@ msgstr "Remover imagem" msgid "Remove image preview" msgstr "Remover visualização da imagem" -#: src/components/dialogs/MutedWords.tsx:294 +#: src/components/dialogs/MutedWords.tsx:343 msgid "Remove mute word from your list" -msgstr "" +msgstr "Remover palavra silenciada da lista" #: src/view/com/modals/Repost.tsx:47 msgid "Remove repost" @@ -3197,7 +3136,8 @@ msgid "Report List" msgstr "Denunciar Lista" #: src/view/com/modals/report/SendReportButton.tsx:37 -#: src/view/com/util/forms/PostDropdownBtn.tsx:255 +#: src/view/com/util/forms/PostDropdownBtn.tsx:301 +#: src/view/com/util/forms/PostDropdownBtn.tsx:309 msgid "Report post" msgstr "Denunciar post" @@ -3243,10 +3183,6 @@ msgstr "Reposts" msgid "Request Change" msgstr "Solicitar Alteração" -#: src/view/com/auth/create/Step2.tsx:219 -#~ msgid "Request code" -#~ msgstr "Solicitar código" - #: src/view/com/modals/ChangePassword.tsx:239 #: src/view/com/modals/ChangePassword.tsx:241 msgid "Request Code" @@ -3256,7 +3192,7 @@ msgstr "Solicitar Código" msgid "Require alt text before posting" msgstr "Exigir texto alternativo antes de postar" -#: src/view/com/auth/create/Step1.tsx:153 +#: src/view/com/auth/create/Step1.tsx:146 msgid "Required for this provider" msgstr "Obrigatório para este provedor" @@ -3321,14 +3257,10 @@ msgstr "Tente novamente" #~ msgid "Retry." #~ msgstr "Tentar novamente." -#: src/view/screens/ProfileList.tsx:898 +#: src/view/screens/ProfileList.tsx:903 msgid "Return to previous page" msgstr "Voltar para página anterior" -#: src/view/shell/desktop/RightNav.tsx:55 -#~ msgid "SANDBOX. Posts and accounts are not permanent." -#~ msgstr "SANDBOX. Posts e contas não são permanentes." - #: src/view/com/lightbox/Lightbox.tsx:132 #: src/view/com/modals/CreateOrEditList.tsx:345 msgctxt "action" @@ -3376,11 +3308,11 @@ msgstr "Salva mudança de usuário para {handle}" msgid "Science" msgstr "Ciência" -#: src/view/screens/ProfileList.tsx:854 +#: src/view/screens/ProfileList.tsx:859 msgid "Scroll to top" msgstr "Ir para o topo" -#: src/Navigation.tsx:440 +#: src/Navigation.tsx:447 #: src/view/com/auth/LoggedOut.tsx:122 #: src/view/com/modals/ListAddRemoveUsers.tsx:75 #: src/view/com/util/forms/SearchInput.tsx:67 @@ -3403,12 +3335,20 @@ msgid "Search for \"{query}\"" msgstr "Pesquisar por \"{query}\"" #: src/components/TagMenu/index.tsx:145 -msgid "Search for all posts by @{authorHandle} with tag {tag}" -msgstr "" +msgid "Search for all posts by @{authorHandle} with tag {displayTag}" +msgstr "Pesquisar por posts de @{authorHandle} com a tag {displayTag}" + +#: src/components/TagMenu/index.tsx:145 +#~ msgid "Search for all posts by @{authorHandle} with tag {tag}" +#~ msgstr "Pesquisar por posts de @{authorHandle} com a tag {tag}" + +#: src/components/TagMenu/index.tsx:94 +msgid "Search for all posts with tag {displayTag}" +msgstr "Pesquisar por posts com a tag {displayTag}" #: src/components/TagMenu/index.tsx:90 -msgid "Search for all posts with tag {tag}" -msgstr "" +#~ msgid "Search for all posts with tag {tag}" +#~ msgstr "Pesquisar por posts com a tag {tag}" #: src/view/com/auth/LoggedOut.tsx:104 #: src/view/com/auth/LoggedOut.tsx:105 @@ -3420,21 +3360,29 @@ msgstr "Buscar usuários" msgid "Security Step Required" msgstr "Passo de Segurança Necessário" -#: src/components/TagMenu/index.web.tsx:50 +#: src/components/TagMenu/index.web.tsx:66 msgid "See {truncatedTag} posts" -msgstr "" +msgstr "Ver posts com {truncatedTag}" -#: src/components/TagMenu/index.web.tsx:67 +#: src/components/TagMenu/index.web.tsx:83 msgid "See {truncatedTag} posts by user" -msgstr "" +msgstr "Ver posts com {truncatedTag} deste usuário" #: src/components/TagMenu/index.tsx:128 -msgid "See <0>{tag}</0> posts" -msgstr "" +msgid "See <0>{displayTag}</0> posts" +msgstr "Ver posts com <0>{displayTag}</0>" + +#: src/components/TagMenu/index.tsx:187 +msgid "See <0>{displayTag}</0> posts by this user" +msgstr "Ver posts com <0>{displayTag}</0> deste usuário" + +#: src/components/TagMenu/index.tsx:128 +#~ msgid "See <0>{tag}</0> posts" +#~ msgstr "Ver posts com <0>{tag}</0>" #: src/components/TagMenu/index.tsx:189 -msgid "See <0>{tag}</0> posts by this user" -msgstr "" +#~ msgid "See <0>{tag}</0> posts by this user" +#~ msgstr "Ver posts com <0>{tag}</0> deste usuário" #: src/view/screens/SavedFeeds.tsx:163 msgid "See this guide" @@ -3448,10 +3396,6 @@ msgstr "Veja o que vem por aÃ" msgid "Select {item}" msgstr "Selecionar {item}" -#: src/view/com/modals/ServerInput.tsx:75 -#~ msgid "Select Bluesky Social" -#~ msgstr "Selecionar Bluesky Social" - #: src/view/com/auth/login/Login.tsx:117 msgid "Select from an existing account" msgstr "Selecionar de uma conta existente" @@ -3460,7 +3404,7 @@ msgstr "Selecionar de uma conta existente" msgid "Select option {i} of {numItems}" msgstr "Seleciona opção {i} de {numItems}" -#: src/view/com/auth/create/Step1.tsx:103 +#: src/view/com/auth/create/Step1.tsx:96 #: src/view/com/auth/login/LoginForm.tsx:150 msgid "Select service" msgstr "Selecionar serviço" @@ -3471,11 +3415,7 @@ msgstr "Selecione algumas contas para seguir" #: src/view/com/auth/server-input/index.tsx:82 msgid "Select the service that hosts your data." -msgstr "" - -#: src/screens/Onboarding/StepModeration/index.tsx:49 -#~ msgid "Select the types of content that you want to see (or not see), and we'll handle the rest." -#~ msgstr "Selecione os tipos de conteúdo que você quer (ou não) ver, e cuidaremos do resto." +msgstr "Selecione o serviço que hospeda seus dados." #: src/screens/Onboarding/StepTopicalFeeds.tsx:96 msgid "Select topical feeds to follow from the list below" @@ -3497,10 +3437,6 @@ msgstr "Selecione o idioma do seu aplicativo" msgid "Select your interests from the options below" msgstr "Selecione seus interesses" -#: src/view/com/auth/create/Step2.tsx:155 -#~ msgid "Select your phone's country" -#~ msgstr "Selecione o paÃs do número de telefone" - #: src/view/screens/LanguageSettings.tsx:190 msgid "Select your preferred language for translations in your feed." msgstr "Selecione seu idioma preferido para as traduções no seu feed." @@ -3542,7 +3478,7 @@ msgstr "Envia o e-mail com o código de confirmação para excluir a conta" #: src/view/com/auth/server-input/index.tsx:110 msgid "Server address" -msgstr "" +msgstr "URL do servidor" #: src/view/com/modals/ContentFilteringSettings.tsx:311 msgid "Set {value} for {labelGroup} content moderation policy" @@ -3578,7 +3514,7 @@ msgstr "Definir o tema escuro para a versão menos escura" msgid "Set new password" msgstr "Definir uma nova senha" -#: src/view/com/auth/create/Step1.tsx:225 +#: src/view/com/auth/create/Step1.tsx:202 msgid "Set password" msgstr "Definir senha" @@ -3598,13 +3534,9 @@ msgstr "Defina esta configuração como \"Não\" para ocultar todos os reposts d msgid "Set this setting to \"Yes\" to show replies in a threaded view. This is an experimental feature." msgstr "Defina esta configuração como \"Sim\" para mostrar respostas em uma visualização de thread. Este é um recurso experimental." -#: src/view/screens/PreferencesHomeFeed.tsx:261 -#~ msgid "Set this setting to \"Yes\" to show samples of your saved feeds in your following feed. This is an experimental feature." -#~ msgstr "Defina esta configuração como \"Sim\" para mostrar amostras de seus feeds salvos na sua página inicial. Este é um recurso experimental." - #: src/view/screens/PreferencesFollowingFeed.tsx:261 msgid "Set this setting to \"Yes\" to show samples of your saved feeds in your Following feed. This is an experimental feature." -msgstr "" +msgstr "Defina esta configuração como \"Sim\" para exibir amostras de seus feeds salvos no seu feed inicial. Este é um recurso experimental." #: src/screens/Onboarding/Layout.tsx:50 msgid "Set up your account" @@ -3622,12 +3554,12 @@ msgstr "Configura o e-mail para recuperação de senha" msgid "Sets hosting provider for password reset" msgstr "Configura o provedor de hospedagem para recuperação de senha" -#: src/view/com/auth/create/Step1.tsx:104 +#: src/view/com/auth/create/Step1.tsx:97 #: src/view/com/auth/login/LoginForm.tsx:151 msgid "Sets server for the Bluesky client" msgstr "Configura o servidor para o cliente do Bluesky" -#: src/Navigation.tsx:135 +#: src/Navigation.tsx:137 #: src/view/screens/Settings/index.tsx:294 #: src/view/shell/desktop/LeftNav.tsx:433 #: src/view/shell/Drawer.tsx:567 @@ -3645,7 +3577,9 @@ msgid "Share" msgstr "Compartilhar" #: src/view/com/profile/ProfileHeader.tsx:295 -#: src/view/com/util/forms/PostDropdownBtn.tsx:184 +#: src/view/com/util/forms/PostDropdownBtn.tsx:231 +#: src/view/com/util/forms/PostDropdownBtn.tsx:237 +#: src/view/com/util/post-ctrls/PostCtrls.tsx:215 #: src/view/screens/ProfileList.tsx:418 msgid "Share" msgstr "Compartilhar" @@ -3737,7 +3671,7 @@ msgstr "Mostrar reposts no Seguindo" msgid "Show the content" msgstr "Mostrar conteúdo" -#: src/view/com/notifications/FeedItem.tsx:346 +#: src/view/com/notifications/FeedItem.tsx:347 msgid "Show users" msgstr "Mostrar usuários" @@ -3832,10 +3766,6 @@ msgstr "Pular" msgid "Skip this flow" msgstr "Pular" -#: src/view/com/auth/create/Step2.tsx:82 -#~ msgid "SMS verification" -#~ msgstr "Verificação por SMS" - #: src/screens/Onboarding/index.tsx:40 msgid "Software Dev" msgstr "Desenvolvimento de software" @@ -3844,11 +3774,15 @@ msgstr "Desenvolvimento de software" #~ msgid "Something went wrong and we're not sure what." #~ msgstr "Algo deu errado e meio que não sabemos o que houve." +#: src/components/Lists.tsx:203 +msgid "Something went wrong!" +msgstr "Algo deu errado!" + #: src/view/com/modals/Waitlist.tsx:51 -msgid "Something went wrong. Check your email and try again." -msgstr "Algo deu errado. Verifique seu e-mail e tente novamente." +#~ msgid "Something went wrong. Check your email and try again." +#~ msgstr "Algo deu errado. Verifique seu e-mail e tente novamente." -#: src/App.native.tsx:63 +#: src/App.native.tsx:66 msgid "Sorry! Your session expired. Please log in again." msgstr "Opa! Sua sessão expirou. Por favor, entre novamente." @@ -3868,10 +3802,6 @@ msgstr "Esportes" msgid "Square" msgstr "Quadrado" -#: src/view/com/modals/ServerInput.tsx:62 -#~ msgid "Staging" -#~ msgstr "Staging" - #: src/view/screens/Settings/index.tsx:871 msgid "Status page" msgstr "Página de status" @@ -3884,7 +3814,7 @@ msgstr "Passo {0} de {numSteps}" msgid "Storage cleared, you need to restart the app now." msgstr "Armazenamento limpo, você precisa reiniciar o app agora." -#: src/Navigation.tsx:202 +#: src/Navigation.tsx:204 #: src/view/screens/Settings/index.tsx:807 msgid "Storybook" msgstr "Storybook" @@ -3898,7 +3828,7 @@ msgid "Subscribe" msgstr "Inscrever-se" #: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:173 -#: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:307 +#: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:308 msgid "Subscribe to the {0} feed" msgstr "Increver-se no feed {0}" @@ -3918,16 +3848,12 @@ msgstr "Sugeridos para você" msgid "Suggestive" msgstr "Sugestivo" -#: src/Navigation.tsx:212 +#: src/Navigation.tsx:214 #: src/view/screens/Support.tsx:30 #: src/view/screens/Support.tsx:33 msgid "Support" msgstr "Suporte" -#: src/view/com/modals/ProfilePreview.tsx:110 -#~ msgid "Swipe up to see more" -#~ msgstr "Deslize para cima para ver mais" - #: src/view/com/modals/SwitchAccount.tsx:117 msgid "Switch Account" msgstr "Alterar Conta" @@ -3950,13 +3876,17 @@ msgstr "Sistema" msgid "System log" msgstr "Log do sistema" -#: src/components/dialogs/MutedWords.tsx:288 +#: src/components/dialogs/MutedWords.tsx:337 msgid "tag" -msgstr "" +msgstr "tag" + +#: src/components/TagMenu/index.tsx:78 +msgid "Tag menu: {displayTag}" +msgstr "Menu da tag: {displayTag}" #: src/components/TagMenu/index.tsx:74 -msgid "Tag menu: {tag}" -msgstr "" +#~ msgid "Tag menu: {tag}" +#~ msgstr "Menu da tag: {tag}" #: src/view/com/modals/crop-image/CropImage.web.tsx:112 msgid "Tall" @@ -3974,16 +3904,16 @@ msgstr "Tecnologia" msgid "Terms" msgstr "Termos" -#: src/Navigation.tsx:222 +#: src/Navigation.tsx:224 #: src/view/screens/Settings/index.tsx:885 #: src/view/screens/TermsOfService.tsx:29 #: src/view/shell/Drawer.tsx:256 msgid "Terms of Service" msgstr "Termos de Serviço" -#: src/components/dialogs/MutedWords.tsx:288 +#: src/components/dialogs/MutedWords.tsx:337 msgid "text" -msgstr "" +msgstr "texto" #: src/view/com/modals/AppealLabel.tsx:70 #: src/view/com/modals/report/InputIssueDetails.tsx:51 @@ -3992,7 +3922,7 @@ msgstr "Campo de entrada de texto" #: src/view/com/auth/create/CreateAccount.tsx:94 msgid "That handle is already taken." -msgstr "" +msgstr "Este identificador de usuário já está sendo usado." #: src/view/com/profile/ProfileHeader.tsx:263 msgid "The account will be able to interact with you after unblocking." @@ -4062,7 +3992,7 @@ msgstr "Tivemos um problema ao contatar o servidor deste feed" msgid "There was an issue fetching notifications. Tap here to try again." msgstr "Tivemos um problema ao carregar notificações. Toque aqui para tentar de novo." -#: src/view/com/posts/Feed.tsx:263 +#: src/view/com/posts/Feed.tsx:265 msgid "There was an issue fetching posts. Tap here to try again." msgstr "Tivemos um problema ao carregar posts. Toque aqui para tentar de novo." @@ -4110,10 +4040,6 @@ msgstr "Houve um problema inesperado no aplicativo. Por favor, deixe-nos saber s msgid "There's been a rush of new users to Bluesky! We'll activate your account as soon as we can." msgstr "Muitos usuários estão tentando acessar o Bluesky! Ativaremos sua conta assim que possÃvel." -#: src/view/com/auth/create/Step2.tsx:55 -#~ msgid "There's something wrong with this number. Please choose your country and enter your full phone number!" -#~ msgstr "Houve um problema com este número. Por favor, escolha um paÃs e digite seu número de telefone completo!" - #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:138 msgid "These are popular accounts you might like:" msgstr "Estas são contas populares que talvez você goste:" @@ -4140,7 +4066,7 @@ msgstr "Este conteúdo não é visÃvel sem uma conta do Bluesky." #: src/view/screens/Settings/ExportCarDialog.tsx:75 msgid "This feature is in beta. You can read more about repository exports in <0>this blogpost.</0>" -msgstr "" +msgstr "Esta funcionalidade está em beta. Você pode ler mais sobre exportação de repositórios <0>neste post</0> do nosso blog." #: src/view/com/posts/FeedErrorMessage.tsx:114 msgid "This feed is currently receiving high traffic and is temporarily unavailable. Please try again later." @@ -4168,7 +4094,7 @@ msgstr "Isso é importante caso você precise alterar seu e-mail ou redefinir su msgid "This link is taking you to the following website:" msgstr "Este link está levando você ao seguinte site:" -#: src/view/screens/ProfileList.tsx:834 +#: src/view/screens/ProfileList.tsx:839 msgid "This list is empty!" msgstr "Esta lista está vazia!" @@ -4192,19 +4118,15 @@ msgstr "Este usuário está incluÃdo na lista <0/>, que você bloqueou." msgid "This user is included in the <0/> list which you have muted." msgstr "Este usuário está incluÃdo na lista <0/>, que você silenciou." -#: src/view/com/modals/ModerationDetails.tsx:74 -#~ msgid "This user is included the <0/> list which you have muted." -#~ msgstr "Este usuário está incluÃdo na lista <0/>, que você silenciou." - #: src/view/com/modals/SelfLabel.tsx:137 msgid "This warning is only available for posts with media attached." msgstr "Este aviso só está disponÃvel para publicações com mÃdia anexada." -#: src/components/dialogs/MutedWords.tsx:236 +#: src/components/dialogs/MutedWords.tsx:285 msgid "This will delete {0} from your muted words. You can always add it back later." -msgstr "" +msgstr "Isso removerá {0} das suas palavras silenciadas. Você pode adicioná-la novamente depois." -#: src/view/com/util/forms/PostDropdownBtn.tsx:237 +#: src/view/com/util/forms/PostDropdownBtn.tsx:282 msgid "This will hide this post from your feeds." msgstr "Isso ocultará este post de seus feeds." @@ -4217,13 +4139,13 @@ msgstr "Preferências das Threads" msgid "Threaded Mode" msgstr "Visualização de Threads" -#: src/Navigation.tsx:255 +#: src/Navigation.tsx:257 msgid "Threads Preferences" msgstr "Preferências das Threads" -#: src/components/dialogs/MutedWords.tsx:95 +#: src/components/dialogs/MutedWords.tsx:113 msgid "Toggle between muted word options." -msgstr "" +msgstr "Alternar entre opções de uma palavra silenciada" #: src/view/com/util/forms/DropdownButton.tsx:246 msgid "Toggle dropdown" @@ -4235,7 +4157,8 @@ msgstr "Transformações" #: src/view/com/post-thread/PostThreadItem.tsx:685 #: src/view/com/post-thread/PostThreadItem.tsx:687 -#: src/view/com/util/forms/PostDropdownBtn.tsx:156 +#: src/view/com/util/forms/PostDropdownBtn.tsx:215 +#: src/view/com/util/forms/PostDropdownBtn.tsx:217 msgid "Translate" msgstr "Traduzir" @@ -4296,28 +4219,32 @@ msgid "Unfortunately, you do not meet the requirements to create an account." msgstr "Infelizmente, você não atende aos requisitos para criar uma conta." #: src/view/com/util/post-ctrls/PostCtrls.tsx:182 -#: src/view/com/util/post-ctrls/PostCtrls.tsx:216 msgid "Unlike" msgstr "Descurtir" -#: src/components/TagMenu/index.tsx:253 +#: src/components/TagMenu/index.tsx:249 #: src/view/screens/ProfileList.tsx:597 msgid "Unmute" msgstr "Dessilenciar" -#: src/components/TagMenu/index.web.tsx:90 +#: src/components/TagMenu/index.web.tsx:104 msgid "Unmute {truncatedTag}" -msgstr "" +msgstr "Dessilenciar {truncatedTag}" #: src/view/com/profile/ProfileHeader.tsx:326 msgid "Unmute Account" msgstr "Dessilenciar conta" +#: src/components/TagMenu/index.tsx:208 +msgid "Unmute all {displayTag} posts" +msgstr "Dessilenciar posts com {displayTag}" + #: src/components/TagMenu/index.tsx:210 -msgid "Unmute all {tag} posts" -msgstr "" +#~ msgid "Unmute all {tag} posts" +#~ msgstr "Dessilenciar posts com {tag}" -#: src/view/com/util/forms/PostDropdownBtn.tsx:202 +#: src/view/com/util/forms/PostDropdownBtn.tsx:251 +#: src/view/com/util/forms/PostDropdownBtn.tsx:256 msgid "Unmute thread" msgstr "Dessilenciar thread" @@ -4372,10 +4299,6 @@ msgstr "Usar o meu navegador padrão" msgid "Use this to sign into the other app along with your handle." msgstr "Use esta senha para entrar no outro aplicativo juntamente com seu identificador." -#: src/view/com/modals/ServerInput.tsx:105 -#~ msgid "Use your domain as your Bluesky client service provider" -#~ msgstr "Use seu domÃnio como o provedor de serviço do Bluesky" - #: src/view/com/modals/InviteCodes.tsx:200 msgid "Used by:" msgstr "Usado por:" @@ -4401,13 +4324,13 @@ msgstr "Usuário" msgid "User list by {0}" msgstr "Lista de usuários por {0}" -#: src/view/screens/ProfileList.tsx:762 +#: src/view/screens/ProfileList.tsx:763 msgid "User list by <0/>" msgstr "Lista de usuários por <0/>" #: src/view/com/lists/ListCard.tsx:83 #: src/view/com/modals/UserAddRemoveLists.tsx:196 -#: src/view/screens/ProfileList.tsx:760 +#: src/view/screens/ProfileList.tsx:761 msgid "User list by you" msgstr "Sua lista de usuários" @@ -4428,7 +4351,7 @@ msgstr "Listas de Usuários" msgid "Username or email address" msgstr "Nome de usuário ou endereço de e-mail" -#: src/view/screens/ProfileList.tsx:796 +#: src/view/screens/ProfileList.tsx:797 msgid "Users" msgstr "Usuários" @@ -4440,10 +4363,6 @@ msgstr "usuários seguidos por <0/>" msgid "Users in \"{0}\"" msgstr "Usuários em \"{0}\"" -#: src/view/com/auth/create/Step2.tsx:243 -#~ msgid "Verification code" -#~ msgstr "Código de verificação" - #: src/view/screens/Settings/index.tsx:910 msgid "Verify email" msgstr "Verificar e-mail" @@ -4502,6 +4421,10 @@ msgstr "Avisar" msgid "We also think you'll like \"For You\" by Skygaze:" msgstr "Também recomendamos o \"For You\", do Skygaze:" +#: src/screens/Hashtag.tsx:132 +msgid "We couldn't find any results for that hashtag." +msgstr "Não encontramos nenhum post com esta hashtag." + #: src/screens/Deactivated.tsx:133 msgid "We estimate {estimatedTime} until your account is ready." msgstr "Estimamos que sua conta estará pronta em mais ou menos {estimatedTime}." @@ -4518,9 +4441,9 @@ msgstr "Não temos mais posts de quem você segue. Aqui estão os mais novos de #~ msgid "We recommend \"For You\" by Skygaze:" #~ msgstr "Recomendamos o \"Para você\", do Skygaze:" -#: src/components/dialogs/MutedWords.tsx:161 +#: src/components/dialogs/MutedWords.tsx:204 msgid "We recommend avoiding common words that appear in many posts, since it can result in no posts being shown." -msgstr "" +msgstr "Não recomendamos utilizar palavras comuns que aparecem em muitos posts, já que isso pode resultar em filtrar todos eles." #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:124 msgid "We recommend our \"Discover\" feed:" @@ -4550,14 +4473,15 @@ msgstr "Estamos muito felizes em recebê-lo!" msgid "We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @{handleOrDid}." msgstr "Tivemos um problema ao exibir esta lista. Se continuar acontecendo, contate o criador da lista: @{handleOrDid}." -#: src/components/dialogs/MutedWords.tsx:182 +#: src/components/dialogs/MutedWords.tsx:230 msgid "We're sorry, but we weren't able to load your muted words at this time. Please try again." -msgstr "" +msgstr "Não foi possÃvel carregar sua lista de palavras silenciadas. Por favor, tente novamente." #: src/view/screens/Search/Search.tsx:254 msgid "We're sorry, but your search could not be completed. Please try again in a few minutes." msgstr "Lamentamos, mas sua busca não pôde ser concluÃda. Por favor, tente novamente em alguns minutos." +#: src/components/Lists.tsx:211 #: src/view/screens/NotFound.tsx:48 msgid "We're sorry! We can't find the page you were looking for." msgstr "Sentimos muito! Não conseguimos encontrar a página que você estava procurando." @@ -4609,10 +4533,6 @@ msgstr "Escreva sua resposta" msgid "Writers" msgstr "Escritores" -#: src/view/com/auth/create/Step2.tsx:263 -#~ msgid "XXXXXX" -#~ msgstr "XXXXXX" - #: src/view/com/composer/select-language/SuggestedLanguage.tsx:77 #: src/view/screens/PreferencesFollowingFeed.tsx:129 #: src/view/screens/PreferencesFollowingFeed.tsx:201 @@ -4623,10 +4543,6 @@ msgstr "Escritores" msgid "Yes" msgstr "Sim" -#: src/screens/Onboarding/StepModeration/index.tsx:46 -#~ msgid "You are in control" -#~ msgstr "Você está no controle" - #: src/screens/Deactivated.tsx:130 msgid "You are in line." msgstr "Você está na fila." @@ -4636,10 +4552,6 @@ msgstr "Você está na fila." msgid "You can also discover new Custom Feeds to follow." msgstr "Você também pode descobrir novos feeds para seguir." -#: src/screens/Onboarding/StepAlgoFeeds/index.tsx:123 -#~ msgid "You can also try our \"Discover\" algorithm:" -#~ msgstr "Você também pode tentar nosso algoritmo \"Discover\":" - #: src/screens/Onboarding/StepFollowingFeed.tsx:142 msgid "You can change these settings later." msgstr "Você pode mudar estas configurações depois." @@ -4705,9 +4617,9 @@ msgstr "Você ainda não criou nenhuma senha de aplicativo. Você pode criar uma msgid "You have not muted any accounts yet. To mute an account, go to their profile and selected \"Mute account\" from the menu on their account." msgstr "Você ainda não silenciou nenhuma conta. Para silenciar uma conta, acesse um perfil e selecione \"Silenciar conta\" no menu." -#: src/components/dialogs/MutedWords.tsx:202 +#: src/components/dialogs/MutedWords.tsx:250 msgid "You haven't muted any words or tags yet" -msgstr "" +msgstr "Você não silenciou nenhuma palavra ou tag ainda" #: src/view/com/modals/ContentFilteringSettings.tsx:175 msgid "You must be 18 or older to enable adult content." @@ -4717,11 +4629,11 @@ msgstr "Você precisa ser maior de idade para habilitar conteúdo adulto." msgid "You must be 18 years or older to enable adult content" msgstr "Você precisa ser maior de idade para habilitar conteúdo adulto." -#: src/view/com/util/forms/PostDropdownBtn.tsx:129 +#: src/view/com/util/forms/PostDropdownBtn.tsx:147 msgid "You will no longer receive notifications for this thread" msgstr "Você não vai mais receber notificações desta thread" -#: src/view/com/util/forms/PostDropdownBtn.tsx:132 +#: src/view/com/util/forms/PostDropdownBtn.tsx:150 msgid "You will now receive notifications for this thread" msgstr "Você vai receber notificações desta thread" @@ -4747,7 +4659,7 @@ msgstr "Tudo pronto!" msgid "You've reached the end of your feed! Find some more accounts to follow." msgstr "Você chegou ao fim do seu feed! Encontre novas contas para seguir." -#: src/view/com/auth/create/Step1.tsx:74 +#: src/view/com/auth/create/Step1.tsx:67 msgid "Your account" msgstr "Sua conta" @@ -4757,9 +4669,9 @@ msgstr "Sua conta foi excluÃda" #: src/view/screens/Settings/ExportCarDialog.tsx:47 msgid "Your account repository, containing all public data records, can be downloaded as a \"CAR\" file. This file does not include media embeds, such as images, or your private data, which must be fetched separately." -msgstr "" +msgstr "O repositório da sua conta, contendo todos os seus dados públicos, pode ser baixado como um arquivo \"CAR\". Este arquivo não inclui imagens ou dados privados, estes devem ser exportados separadamente." -#: src/view/com/auth/create/Step1.tsx:238 +#: src/view/com/auth/create/Step1.tsx:215 msgid "Your birth date" msgstr "Sua data de nascimento" @@ -4778,8 +4690,8 @@ msgid "Your email appears to be invalid." msgstr "Seu e-mail parece ser inválido." #: src/view/com/modals/Waitlist.tsx:109 -msgid "Your email has been saved! We'll be in touch soon." -msgstr "Seu e-mail foi salvo! Logo entraremos em contato." +#~ msgid "Your email has been saved! We'll be in touch soon." +#~ msgstr "Seu e-mail foi salvo! Logo entraremos em contato." #: src/view/com/modals/ChangeEmail.tsx:125 msgid "Your email has been updated but not verified. As a next step, please verify your new email." @@ -4807,9 +4719,9 @@ msgstr "Seu usuário completo será <0>@{0}</0>" #~ msgid "Your invite codes are hidden when logged in using an App Password" #~ msgstr "Seus códigos de convite estão ocultos quando conectado com uma Senha do Aplicativo" -#: src/components/dialogs/MutedWords.tsx:173 +#: src/components/dialogs/MutedWords.tsx:221 msgid "Your muted words" -msgstr "" +msgstr "Suas palavras silenciadas" #: src/view/com/modals/ChangePassword.tsx:155 msgid "Your password has been changed successfully!" diff --git a/src/locale/locales/uk/messages.po b/src/locale/locales/uk/messages.po index 8f978261f..41782f776 100644 --- a/src/locale/locales/uk/messages.po +++ b/src/locale/locales/uk/messages.po @@ -117,12 +117,12 @@ msgstr "ÐŸÐ¾Ð¿ÐµÑ€ÐµÐ´Ð¶ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ вміÑÑ‚ було додано до ц msgid "A new version of the app is available. Please update to continue using the app." msgstr "ДоÑтупна нова верÑÑ–Ñ. Будь лаÑка, оновіть заÑтоÑунок, щоб продовжити ним кориÑтуватиÑÑ." -#: src/view/com/util/ViewHeader.tsx:83 +#: src/view/com/util/ViewHeader.tsx:89 #: src/view/screens/Search/Search.tsx:647 msgid "Access navigation links and settings" msgstr "" -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:51 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:52 msgid "Access profile and other navigation links" msgstr "" @@ -169,11 +169,11 @@ msgstr "" msgid "Account unmuted" msgstr "" -#: src/components/dialogs/MutedWords.tsx:147 +#: src/components/dialogs/MutedWords.tsx:165 #: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:150 #: src/view/com/modals/ListAddRemoveUsers.tsx:264 #: src/view/com/modals/UserAddRemoveLists.tsx:219 -#: src/view/screens/ProfileList.tsx:812 +#: src/view/screens/ProfileList.tsx:813 msgid "Add" msgstr "Додати" @@ -181,7 +181,7 @@ msgstr "Додати" msgid "Add a content warning" msgstr "Додати Ð¿Ð¾Ð¿ÐµÑ€ÐµÐ´Ð¶ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ вміÑÑ‚" -#: src/view/screens/ProfileList.tsx:802 +#: src/view/screens/ProfileList.tsx:803 msgid "Add a user to this list" msgstr "Додати кориÑтувача до ÑпиÑку" @@ -219,11 +219,11 @@ msgstr "Додати попередній переглÑд" msgid "Add link card:" msgstr "Додати попередній переглÑд:" -#: src/components/dialogs/MutedWords.tsx:140 +#: src/components/dialogs/MutedWords.tsx:158 msgid "Add mute word for configured settings" msgstr "" -#: src/components/dialogs/MutedWords.tsx:74 +#: src/components/dialogs/MutedWords.tsx:87 msgid "Add muted words and tags" msgstr "" @@ -311,7 +311,7 @@ msgstr "Було надіÑлано лиÑÑ‚ на вашу попередню а msgid "An issue occurred, please try again." msgstr "" -#: src/view/com/notifications/FeedItem.tsx:236 +#: src/view/com/notifications/FeedItem.tsx:237 #: src/view/com/threadgate/WhoCanReply.tsx:178 msgid "and" msgstr "та" @@ -344,13 +344,14 @@ msgstr "" #~ msgid "App passwords" #~ msgstr "Паролі Ð´Ð»Ñ Ð·Ð°ÑтоÑунків" -#: src/Navigation.tsx:237 +#: src/Navigation.tsx:239 #: src/view/screens/AppPasswords.tsx:187 #: src/view/screens/Settings/index.tsx:684 msgid "App Passwords" msgstr "Паролі Ð´Ð»Ñ Ð·Ð°ÑтоÑунків" -#: src/view/com/util/forms/PostDropdownBtn.tsx:295 +#: src/view/com/util/forms/PostDropdownBtn.tsx:337 +#: src/view/com/util/forms/PostDropdownBtn.tsx:346 msgid "Appeal content warning" msgstr "ОÑкаржити Ð¿Ð¾Ð¿ÐµÑ€ÐµÐ´Ð¶ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾ вміÑÑ‚" @@ -386,12 +387,12 @@ msgstr "Ви дійÑно хочете видалити пароль Ð´Ð»Ñ Ð·Ð° msgid "Are you sure you'd like to discard this draft?" msgstr "Ви дійÑно бажаєте видалити цю чернетку?" -#: src/components/dialogs/MutedWords.tsx:233 +#: src/components/dialogs/MutedWords.tsx:282 #: src/view/screens/ProfileList.tsx:365 msgid "Are you sure?" msgstr "Ви впевнені?" -#: src/view/com/util/forms/PostDropdownBtn.tsx:278 +#: src/view/com/util/forms/PostDropdownBtn.tsx:322 msgid "Are you sure? This cannot be undone." msgstr "Ви впевнені? Це не можна буде ÑкаÑувати." @@ -421,7 +422,7 @@ msgstr "Ð¥ÑƒÐ´Ð¾Ð¶Ð½Ñ Ð°Ð±Ð¾ нееротична оголеніÑть." #: src/view/com/post-thread/PostThread.tsx:522 #: src/view/com/post-thread/PostThread.tsx:530 #: src/view/com/profile/ProfileHeader.tsx:649 -#: src/view/com/util/ViewHeader.tsx:81 +#: src/view/com/util/ViewHeader.tsx:87 msgid "Back" msgstr "Ðазад" @@ -438,7 +439,7 @@ msgstr "" msgid "Basics" msgstr "ОÑновні" -#: src/view/com/auth/create/Step1.tsx:250 +#: src/view/com/auth/create/Step1.tsx:227 #: src/view/com/modals/BirthDateSettings.tsx:73 msgid "Birthday" msgstr "Дата народженнÑ" @@ -477,7 +478,7 @@ msgstr "" msgid "Blocked accounts" msgstr "Заблоковані облікові запиÑи" -#: src/Navigation.tsx:130 +#: src/Navigation.tsx:132 #: src/view/screens/ModerationBlockedAccounts.tsx:107 msgid "Blocked Accounts" msgstr "Заблоковані облікові запиÑи" @@ -529,8 +530,8 @@ msgid "Bluesky is public." msgstr "Bluesky публічний." #: src/view/com/modals/Waitlist.tsx:70 -msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon." -msgstr "Bluesky викориÑтовує ÑиÑтему запрошень Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð·Ð´Ð¾Ñ€Ð¾Ð²Ñ–ÑˆÐ¾Ñ— Ñпільноти. Якщо Ви не знаєте когоÑÑŒ хто має запрошеннÑ, ви можете запиÑатиÑÑ Ð´Ð¾ черги Ð¾Ñ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ñ– ми Ñкоро надішлемо вам код запрошеннÑ." +#~ msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon." +#~ msgstr "Bluesky викориÑтовує ÑиÑтему запрошень Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð·Ð´Ð¾Ñ€Ð¾Ð²Ñ–ÑˆÐ¾Ñ— Ñпільноти. Якщо Ви не знаєте когоÑÑŒ хто має запрошеннÑ, ви можете запиÑатиÑÑ Ð´Ð¾ черги Ð¾Ñ‡Ñ–ÐºÑƒÐ²Ð°Ð½Ð½Ñ Ñ– ми Ñкоро надішлемо вам код запрошеннÑ." #: src/view/screens/Moderation.tsx:245 msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private." @@ -583,7 +584,7 @@ msgstr "Камера" msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must be at least 4 characters long, but no more than 32 characters long." msgstr "Може міÑтити лише літери, цифри, пробіли, дефіÑи та знаки підкреÑленнÑ, Ñ– мати довжину від 4 до 32 Ñимволів." -#: src/components/Prompt.tsx:91 +#: src/components/Prompt.tsx:101 #: src/view/com/composer/Composer.tsx:307 #: src/view/com/composer/Composer.tsx:312 #: src/view/com/modals/ChangeEmail.tsx:218 @@ -598,7 +599,6 @@ msgstr "Може міÑтити лише літери, цифри, пробілР#: src/view/com/modals/Repost.tsx:87 #: src/view/com/modals/VerifyEmail.tsx:247 #: src/view/com/modals/VerifyEmail.tsx:253 -#: src/view/com/modals/Waitlist.tsx:142 #: src/view/screens/Search/Search.tsx:716 #: src/view/shell/desktop/Search.tsx:238 msgid "Cancel" @@ -644,8 +644,8 @@ msgid "Cancel search" msgstr "СкаÑувати пошук" #: src/view/com/modals/Waitlist.tsx:136 -msgid "Cancel waitlist signup" -msgstr "СкаÑувати Ð·Ð°Ð¿Ð¸Ñ Ñƒ чергу очікуваннÑ" +#~ msgid "Cancel waitlist signup" +#~ msgstr "СкаÑувати Ð·Ð°Ð¿Ð¸Ñ Ñƒ чергу очікуваннÑ" #: src/view/screens/Settings/index.tsx:334 msgctxt "action" @@ -739,7 +739,7 @@ msgstr "Ðвтори Ñтрічок можуть обирати будь-Ñкі msgid "Choose your main feeds" msgstr "" -#: src/view/com/auth/create/Step1.tsx:219 +#: src/view/com/auth/create/Step1.tsx:196 msgid "Choose your password" msgstr "Вкажіть пароль" @@ -770,11 +770,14 @@ msgstr "ОчиÑтити пошуковий запит" msgid "click here" msgstr "" -#: src/components/RichText.tsx:189 -#: src/components/TagMenu/index.web.tsx:125 +#: src/components/TagMenu/index.web.tsx:138 msgid "Click here to open tag menu for {tag}" msgstr "" +#: src/components/RichText.tsx:191 +msgid "Click here to open tag menu for #{tag}" +msgstr "" + #: src/screens/Onboarding/index.tsx:35 msgid "Climate" msgstr "" @@ -784,8 +787,8 @@ msgstr "" msgid "Close" msgstr "" -#: src/components/Dialog/index.web.tsx:80 -#: src/components/Dialog/index.web.tsx:194 +#: src/components/Dialog/index.web.tsx:84 +#: src/components/Dialog/index.web.tsx:198 msgid "Close active dialog" msgstr "" @@ -809,7 +812,7 @@ msgstr "Закрити переглÑд зображеннÑ" msgid "Close navigation footer" msgstr "Закрити панель навігації" -#: src/components/TagMenu/index.tsx:266 +#: src/components/TagMenu/index.tsx:262 msgid "Close this dialog" msgstr "" @@ -829,7 +832,7 @@ msgstr "" msgid "Closes viewer for header image" msgstr "" -#: src/view/com/notifications/FeedItem.tsx:317 +#: src/view/com/notifications/FeedItem.tsx:318 msgid "Collapses list of users for a given notification" msgstr "" @@ -841,7 +844,7 @@ msgstr "" msgid "Comics" msgstr "" -#: src/Navigation.tsx:227 +#: src/Navigation.tsx:229 #: src/view/screens/CommunityGuidelines.tsx:32 msgid "Community Guidelines" msgstr "Правила Ñпільноти" @@ -866,7 +869,7 @@ msgstr "ВідповіÑти" msgid "Configure content filtering setting for category: {0}" msgstr "" -#: src/components/Prompt.tsx:113 +#: src/components/Prompt.tsx:124 #: src/view/com/modals/AppealLabel.tsx:98 #: src/view/com/modals/SelfLabel.tsx:154 #: src/view/com/modals/VerifyEmail.tsx:231 @@ -906,8 +909,8 @@ msgid "Confirmation code" msgstr "Код підтвердженнÑ" #: src/view/com/modals/Waitlist.tsx:120 -msgid "Confirms signing up {email} to the waitlist" -msgstr "" +#~ msgid "Confirms signing up {email} to the waitlist" +#~ msgstr "" #: src/view/com/auth/create/CreateAccount.tsx:193 #: src/view/com/auth/login/LoginForm.tsx:278 @@ -984,7 +987,7 @@ msgstr "" #: src/view/com/modals/AddAppPasswords.tsx:76 #: src/view/com/modals/InviteCodes.tsx:152 -#: src/view/com/util/forms/PostDropdownBtn.tsx:143 +#: src/view/com/util/forms/PostDropdownBtn.tsx:161 msgid "Copied to clipboard" msgstr "" @@ -1000,7 +1003,8 @@ msgstr "Скопіювати" msgid "Copy link to list" msgstr "Скопіювати поÑиланнÑ" -#: src/view/com/util/forms/PostDropdownBtn.tsx:184 +#: src/view/com/util/forms/PostDropdownBtn.tsx:231 +#: src/view/com/util/forms/PostDropdownBtn.tsx:237 msgid "Copy link to post" msgstr "Скопіювати поÑиланнÑ" @@ -1008,11 +1012,12 @@ msgstr "Скопіювати поÑиланнÑ" msgid "Copy link to profile" msgstr "Скопіювати поÑиланнÑ" -#: src/view/com/util/forms/PostDropdownBtn.tsx:170 +#: src/view/com/util/forms/PostDropdownBtn.tsx:223 +#: src/view/com/util/forms/PostDropdownBtn.tsx:225 msgid "Copy post text" msgstr "Скопіювати текÑÑ‚" -#: src/Navigation.tsx:232 +#: src/Navigation.tsx:234 #: src/view/screens/CopyrightPolicy.tsx:29 msgid "Copyright Policy" msgstr "Політика захиÑту авторÑького права" @@ -1021,7 +1026,7 @@ msgstr "Політика захиÑту авторÑького права" msgid "Could not load feed" msgstr "Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ Ñтрічку" -#: src/view/screens/ProfileList.tsx:888 +#: src/view/screens/ProfileList.tsx:893 msgid "Could not load list" msgstr "Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ ÑпиÑок" @@ -1145,11 +1150,12 @@ msgstr "Видалити мій обліковий запиÑ" msgid "Delete My Account…" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:273 +#: src/view/com/util/forms/PostDropdownBtn.tsx:317 +#: src/view/com/util/forms/PostDropdownBtn.tsx:326 msgid "Delete post" msgstr "Видалити поÑÑ‚" -#: src/view/com/util/forms/PostDropdownBtn.tsx:277 +#: src/view/com/util/forms/PostDropdownBtn.tsx:321 msgid "Delete this post?" msgstr "Видалити цей поÑÑ‚?" @@ -1222,8 +1228,8 @@ msgid "Domain verified!" msgstr "Домен перевірено!" #: src/view/com/auth/create/Step1.tsx:170 -msgid "Don't have an invite code?" -msgstr "" +#~ msgid "Don't have an invite code?" +#~ msgstr "" #: src/view/com/auth/onboarding/RecommendedFollows.tsx:86 #: src/view/com/modals/EditImage.tsx:333 @@ -1325,7 +1331,7 @@ msgstr "Редагувати Ð¾Ð¿Ð¸Ñ ÑпиÑку" msgid "Edit Moderation List" msgstr "" -#: src/Navigation.tsx:242 +#: src/Navigation.tsx:244 #: src/view/screens/Feeds.tsx:434 #: src/view/screens/SavedFeeds.tsx:84 msgid "Edit My Feeds" @@ -1343,7 +1349,7 @@ msgstr "Редагувати профіль" msgid "Edit Profile" msgstr "Редагувати профіль" -#: src/view/com/home/HomeHeaderLayout.web.tsx:59 +#: src/view/com/home/HomeHeaderLayout.web.tsx:62 #: src/view/screens/Feeds.tsx:355 msgid "Edit Saved Feeds" msgstr "Редагувати збережені Ñтрічки" @@ -1364,14 +1370,13 @@ msgstr "" msgid "Education" msgstr "" -#: src/view/com/auth/create/Step1.tsx:199 +#: src/view/com/auth/create/Step1.tsx:176 #: src/view/com/auth/login/ForgotPasswordForm.tsx:156 #: src/view/com/modals/ChangeEmail.tsx:141 -#: src/view/com/modals/Waitlist.tsx:88 msgid "Email" msgstr "Ел. адреÑа" -#: src/view/com/auth/create/Step1.tsx:190 +#: src/view/com/auth/create/Step1.tsx:167 #: src/view/com/auth/login/ForgotPasswordForm.tsx:147 msgid "Email address" msgstr "ÐдреÑа електронної пошти" @@ -1426,8 +1431,8 @@ msgstr "Кінець Ñтрічки" msgid "Enter a name for this App Password" msgstr "" -#: src/components/dialogs/MutedWords.tsx:87 -#: src/components/dialogs/MutedWords.tsx:88 +#: src/components/dialogs/MutedWords.tsx:100 +#: src/components/dialogs/MutedWords.tsx:101 msgid "Enter a word or tag" msgstr "" @@ -1451,16 +1456,16 @@ msgstr "Введіть домен, Ñкий ви хочете викориÑто msgid "Enter the email you used to create your account. We'll send you a \"reset code\" so you can set a new password." msgstr "Введіть адреÑу електронної пошти, Ñку ви викориÑтовували Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¾Ð±Ð»Ñ–ÐºÐ¾Ð²Ð¾Ð³Ð¾ запиÑу. Ми надішлемо вам код підтвердженнÑ, щоб ви могли вÑтановити новий пароль." -#: src/view/com/auth/create/Step1.tsx:251 +#: src/view/com/auth/create/Step1.tsx:228 #: src/view/com/modals/BirthDateSettings.tsx:74 msgid "Enter your birth date" msgstr "" #: src/view/com/modals/Waitlist.tsx:78 -msgid "Enter your email" -msgstr "" +#~ msgid "Enter your email" +#~ msgstr "" -#: src/view/com/auth/create/Step1.tsx:195 +#: src/view/com/auth/create/Step1.tsx:172 msgid "Enter your email address" msgstr "Введіть адреÑу електронної пошти" @@ -1506,8 +1511,8 @@ msgid "Exits inputting search query" msgstr "" #: src/view/com/modals/Waitlist.tsx:138 -msgid "Exits signing up for waitlist with {email}" -msgstr "" +#~ msgid "Exits signing up for waitlist with {email}" +#~ msgstr "" #: src/view/com/lightbox/Lightbox.web.tsx:163 msgid "Expand alt text" @@ -1536,7 +1541,7 @@ msgstr "Зовнішні медіа" msgid "External media may allow websites to collect information about you and your device. No information is sent or requested until you press the \"play\" button." msgstr "Зовнішні медіа можуть дозволÑти вебÑайтам збирати інформацію про Ð²Ð°Ñ Ñ‚Ð° ваш приÑтрій. Ð†Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ñ–Ñ Ð½Ðµ надÑилаєтьÑÑ Ñ‚Ð° не запитуєтьÑÑ, допоки не натиÑнуто кнопку «Відтворити»." -#: src/Navigation.tsx:261 +#: src/Navigation.tsx:263 #: src/view/screens/PreferencesExternalEmbeds.tsx:52 #: src/view/screens/Settings/index.tsx:657 msgid "External Media Preferences" @@ -1555,7 +1560,7 @@ msgstr "" msgid "Failed to create the list. Check your internet connection and try again." msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:110 +#: src/view/com/util/forms/PostDropdownBtn.tsx:128 msgid "Failed to delete post, please try again" msgstr "" @@ -1564,7 +1569,7 @@ msgstr "" msgid "Failed to load recommended feeds" msgstr "Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ рекомендації Ñтрічок" -#: src/Navigation.tsx:192 +#: src/Navigation.tsx:194 msgid "Feed" msgstr "" @@ -1585,7 +1590,7 @@ msgstr "Стрічка не працює" msgid "Feedback" msgstr "ÐадіÑлати відгук" -#: src/Navigation.tsx:445 +#: src/Navigation.tsx:452 #: src/view/screens/Feeds.tsx:419 #: src/view/screens/Feeds.tsx:524 #: src/view/screens/Profile.tsx:184 @@ -1738,9 +1743,9 @@ msgstr "ПідпиÑані" msgid "Following {0}" msgstr "" -#: src/Navigation.tsx:248 -#: src/view/com/home/HomeHeaderLayout.web.tsx:45 -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:83 +#: src/Navigation.tsx:250 +#: src/view/com/home/HomeHeaderLayout.web.tsx:50 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:84 #: src/view/screens/PreferencesFollowingFeed.tsx:104 #: src/view/screens/Settings/index.tsx:543 msgid "Following Feed Preferences" @@ -1779,6 +1784,11 @@ msgstr "Забули пароль" msgid "Forgot Password" msgstr "Забули пароль" +#: src/screens/Hashtag.tsx:108 +#: src/screens/Hashtag.tsx:148 +msgid "From @{sanitizedAuthor}" +msgstr "" + #: src/view/com/posts/FeedItem.tsx:189 msgctxt "from-feed" msgid "From <0/>" @@ -1802,8 +1812,8 @@ msgstr "Ðазад" #: src/view/screens/ProfileFeed.tsx:106 #: src/view/screens/ProfileFeed.tsx:111 -#: src/view/screens/ProfileList.tsx:897 #: src/view/screens/ProfileList.tsx:902 +#: src/view/screens/ProfileList.tsx:907 msgid "Go Back" msgstr "Ðазад" @@ -1829,8 +1839,16 @@ msgstr "Далі" msgid "Handle" msgstr "ПÑевдонім" +#: src/Navigation.tsx:270 +msgid "Hashtag" +msgstr "" + #: src/components/RichText.tsx:188 -msgid "Hashtag: {tag}" +#~ msgid "Hashtag: {tag}" +#~ msgstr "" + +#: src/components/RichText.tsx:190 +msgid "Hashtag: #{tag}" msgstr "" #: src/view/com/auth/create/CreateAccount.tsx:208 @@ -1870,12 +1888,13 @@ msgid "Hide" msgstr "Приховати" #: src/view/com/modals/ContentFilteringSettings.tsx:224 -#: src/view/com/notifications/FeedItem.tsx:325 +#: src/view/com/notifications/FeedItem.tsx:326 msgctxt "action" msgid "Hide" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:232 +#: src/view/com/util/forms/PostDropdownBtn.tsx:276 +#: src/view/com/util/forms/PostDropdownBtn.tsx:287 msgid "Hide post" msgstr "Приховати поÑÑ‚" @@ -1884,11 +1903,11 @@ msgstr "Приховати поÑÑ‚" msgid "Hide the content" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:236 +#: src/view/com/util/forms/PostDropdownBtn.tsx:280 msgid "Hide this post?" msgstr "Приховати цей поÑÑ‚?" -#: src/view/com/notifications/FeedItem.tsx:315 +#: src/view/com/notifications/FeedItem.tsx:316 msgid "Hide user list" msgstr "Приховати ÑпиÑок кориÑтувачів" @@ -1924,7 +1943,7 @@ msgstr "Хм, ми не можемо знайти цю Ñтрічку. МожлР#~ msgid "Hmmm, we're having trouble finding this feed. It may have been deleted." #~ msgstr "" -#: src/Navigation.tsx:435 +#: src/Navigation.tsx:442 #: src/view/shell/bottom-bar/BottomBar.tsx:137 #: src/view/shell/desktop/LeftNav.tsx:306 #: src/view/shell/Drawer.tsx:398 @@ -1939,7 +1958,7 @@ msgstr "Головна" #~ msgid "Home Feed Preferences" #~ msgstr "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð´Ð¾Ð¼Ð°ÑˆÐ½ÑŒÐ¾Ñ— Ñтрічки" -#: src/view/com/auth/create/Step1.tsx:82 +#: src/view/com/auth/create/Step1.tsx:75 #: src/view/com/auth/login/ForgotPasswordForm.tsx:120 msgid "Hosting provider" msgstr "ХоÑтинг-провайдер" @@ -2003,7 +2022,7 @@ msgstr "" msgid "Input confirmation code for account deletion" msgstr "" -#: src/view/com/auth/create/Step1.tsx:200 +#: src/view/com/auth/create/Step1.tsx:177 msgid "Input email for Bluesky account" msgstr "" @@ -2015,7 +2034,7 @@ msgstr "" #~ msgid "Input hosting provider address" #~ msgstr "" -#: src/view/com/auth/create/Step1.tsx:158 +#: src/view/com/auth/create/Step1.tsx:151 msgid "Input invite code to proceed" msgstr "" @@ -2048,8 +2067,8 @@ msgstr "" #~ msgstr "" #: src/view/com/modals/Waitlist.tsx:90 -msgid "Input your email to get on the Bluesky waitlist" -msgstr "" +#~ msgid "Input your email to get on the Bluesky waitlist" +#~ msgstr "" #: src/view/com/auth/login/LoginForm.tsx:229 msgid "Input your password" @@ -2075,8 +2094,8 @@ msgstr "Ðевірне ім'Ñ ÐºÐ¾Ñ€Ð¸Ñтувача або пароль" msgid "Invite a Friend" msgstr "ЗапроÑити друга" -#: src/view/com/auth/create/Step1.tsx:148 -#: src/view/com/auth/create/Step1.tsx:157 +#: src/view/com/auth/create/Step1.tsx:141 +#: src/view/com/auth/create/Step1.tsx:150 msgid "Invite code" msgstr "Код запрошеннÑ" @@ -2106,17 +2125,17 @@ msgid "Jobs" msgstr "ВаканÑÑ–Ñ—" #: src/view/com/modals/Waitlist.tsx:67 -msgid "Join the waitlist" -msgstr "ПриєднатиÑÑ Ð´Ð¾ черги очікуваннÑ" +#~ msgid "Join the waitlist" +#~ msgstr "ПриєднатиÑÑ Ð´Ð¾ черги очікуваннÑ" #: src/view/com/auth/create/Step1.tsx:174 #: src/view/com/auth/create/Step1.tsx:178 -msgid "Join the waitlist." -msgstr "ПриєднатиÑÑ Ð´Ð¾ черги очікуваннÑ." +#~ msgid "Join the waitlist." +#~ msgstr "ПриєднатиÑÑ Ð´Ð¾ черги очікуваннÑ." #: src/view/com/modals/Waitlist.tsx:128 -msgid "Join Waitlist" -msgstr "ПриєднатиÑÑ Ð´Ð¾ черги очікуваннÑ" +#~ msgid "Join Waitlist" +#~ msgstr "ПриєднатиÑÑ Ð´Ð¾ черги очікуваннÑ" #: src/screens/Onboarding/index.tsx:24 msgid "Journalism" @@ -2130,7 +2149,7 @@ msgstr "Вибір мови" msgid "Language settings" msgstr "" -#: src/Navigation.tsx:140 +#: src/Navigation.tsx:142 #: src/view/screens/LanguageSettings.tsx:89 msgid "Language Settings" msgstr "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¼Ð¾Ð²" @@ -2200,7 +2219,6 @@ msgid "Light" msgstr "" #: src/view/com/util/post-ctrls/PostCtrls.tsx:182 -#: src/view/com/util/post-ctrls/PostCtrls.tsx:216 msgid "Like" msgstr "" @@ -2208,7 +2226,7 @@ msgstr "" msgid "Like this feed" msgstr "Вподобати цю Ñтрічку" -#: src/Navigation.tsx:197 +#: src/Navigation.tsx:199 msgid "Liked by" msgstr "СподобалоÑÑ" @@ -2257,7 +2275,7 @@ msgstr "" #~ msgid "Limit the visibility of my account to logged-out users" #~ msgstr "" -#: src/Navigation.tsx:166 +#: src/Navigation.tsx:168 msgid "List" msgstr "" @@ -2293,7 +2311,7 @@ msgstr "" msgid "List unmuted" msgstr "" -#: src/Navigation.tsx:110 +#: src/Navigation.tsx:112 #: src/view/screens/Profile.tsx:185 #: src/view/shell/desktop/LeftNav.tsx:379 #: src/view/shell/Drawer.tsx:492 @@ -2325,7 +2343,7 @@ msgstr "ЗавантаженнÑ..." #~ msgid "Local dev server" #~ msgstr "Локальний Ñервер розробки" -#: src/Navigation.tsx:207 +#: src/Navigation.tsx:209 msgid "Log" msgstr "" @@ -2356,7 +2374,7 @@ msgstr "Увійти до облікового запиÑу, Ñкого нема msgid "Make sure this is where you intend to go!" msgstr "ПереконайтеÑÑ, що це дійÑно той Ñайт, що ви збираєтеÑÑ Ð²Ñ–Ð´Ð²Ñ–Ð´Ð°Ñ‚Ð¸!" -#: src/components/dialogs/MutedWords.tsx:71 +#: src/components/dialogs/MutedWords.tsx:83 msgid "Manage your muted words and tags" msgstr "" @@ -2380,7 +2398,7 @@ msgstr "згадані кориÑтувачі" msgid "Mentioned users" msgstr "Згадані кориÑтувачі" -#: src/view/com/util/ViewHeader.tsx:81 +#: src/view/com/util/ViewHeader.tsx:87 #: src/view/screens/Search/Search.tsx:646 msgid "Menu" msgstr "Меню" @@ -2393,7 +2411,7 @@ msgstr "Меню" msgid "Message from server: {0}" msgstr "" -#: src/Navigation.tsx:115 +#: src/Navigation.tsx:117 #: src/view/screens/Moderation.tsx:66 #: src/view/screens/Settings/index.tsx:625 #: src/view/shell/desktop/LeftNav.tsx:397 @@ -2407,13 +2425,13 @@ msgstr "МодераціÑ" msgid "Moderation list by {0}" msgstr "" -#: src/view/screens/ProfileList.tsx:774 +#: src/view/screens/ProfileList.tsx:775 msgid "Moderation list by <0/>" msgstr "" #: src/view/com/lists/ListCard.tsx:91 #: src/view/com/modals/UserAddRemoveLists.tsx:204 -#: src/view/screens/ProfileList.tsx:772 +#: src/view/screens/ProfileList.tsx:773 msgid "Moderation list by you" msgstr "" @@ -2429,7 +2447,7 @@ msgstr "" msgid "Moderation lists" msgstr "СпиÑки Ð´Ð»Ñ Ð¼Ð¾Ð´ÐµÑ€Ð°Ñ†Ñ–Ñ—" -#: src/Navigation.tsx:120 +#: src/Navigation.tsx:122 #: src/view/screens/ModerationModlists.tsx:58 msgid "Moderation Lists" msgstr "СпиÑки Ð´Ð»Ñ Ð¼Ð¾Ð´ÐµÑ€Ð°Ñ†Ñ–Ñ—" @@ -2442,7 +2460,7 @@ msgstr "" msgid "Moderator has chosen to set a general warning on the content." msgstr "" -#: src/view/shell/desktop/Feeds.tsx:63 +#: src/view/shell/desktop/Feeds.tsx:65 msgid "More feeds" msgstr "Більше Ñтрічок" @@ -2453,8 +2471,8 @@ msgid "More options" msgstr "Додаткові опції" #: src/view/com/util/forms/PostDropdownBtn.tsx:315 -msgid "More post options" -msgstr "" +#~ msgid "More post options" +#~ msgstr "" #: src/view/screens/PreferencesThreads.tsx:82 msgid "Most-liked replies first" @@ -2464,11 +2482,11 @@ msgstr "За кількіÑтю вподобань" msgid "Must be at least 3 characters" msgstr "" -#: src/components/TagMenu/index.tsx:253 +#: src/components/TagMenu/index.tsx:249 msgid "Mute" msgstr "" -#: src/components/TagMenu/index.web.tsx:91 +#: src/components/TagMenu/index.web.tsx:105 msgid "Mute {truncatedTag}" msgstr "" @@ -2480,15 +2498,19 @@ msgstr "Ігнорувати обліковий запиÑ" msgid "Mute accounts" msgstr "Ігнорувати облікові запиÑи" -#: src/components/TagMenu/index.tsx:211 -msgid "Mute all {tag} posts" +#: src/components/TagMenu/index.tsx:209 +msgid "Mute all {displayTag} posts" msgstr "" -#: src/components/dialogs/MutedWords.tsx:131 +#: src/components/TagMenu/index.tsx:211 +#~ msgid "Mute all {tag} posts" +#~ msgstr "" + +#: src/components/dialogs/MutedWords.tsx:149 msgid "Mute in tags only" msgstr "" -#: src/components/dialogs/MutedWords.tsx:116 +#: src/components/dialogs/MutedWords.tsx:134 msgid "Mute in text & tags" msgstr "" @@ -2504,19 +2526,21 @@ msgstr "Ігнорувати ці облікові запиÑи?" msgid "Mute this List" msgstr "" -#: src/components/dialogs/MutedWords.tsx:109 +#: src/components/dialogs/MutedWords.tsx:127 msgid "Mute this word in post text and tags" msgstr "" -#: src/components/dialogs/MutedWords.tsx:124 +#: src/components/dialogs/MutedWords.tsx:142 msgid "Mute this word in tags only" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:202 +#: src/view/com/util/forms/PostDropdownBtn.tsx:251 +#: src/view/com/util/forms/PostDropdownBtn.tsx:257 msgid "Mute thread" msgstr "Ігнорувати поÑÑ‚" -#: src/view/com/util/forms/PostDropdownBtn.tsx:216 +#: src/view/com/util/forms/PostDropdownBtn.tsx:267 +#: src/view/com/util/forms/PostDropdownBtn.tsx:269 msgid "Mute words & tags" msgstr "" @@ -2528,7 +2552,7 @@ msgstr "" msgid "Muted accounts" msgstr "Ігноровані облікові запиÑи" -#: src/Navigation.tsx:125 +#: src/Navigation.tsx:127 #: src/view/screens/ModerationMutedAccounts.tsx:107 msgid "Muted Accounts" msgstr "Ігноровані облікові запиÑи" @@ -2608,7 +2632,7 @@ msgstr "Ðіколи не втрачайте доÑтуп до ваших дан msgid "Never lose access to your followers or data." msgstr "" -#: src/components/dialogs/MutedWords.tsx:244 +#: src/components/dialogs/MutedWords.tsx:293 msgid "Nevermind" msgstr "" @@ -2700,7 +2724,7 @@ msgid "No" msgstr "ÐÑ–" #: src/view/screens/ProfileFeed.tsx:584 -#: src/view/screens/ProfileList.tsx:754 +#: src/view/screens/ProfileList.tsx:755 msgid "No description" msgstr "ÐžÐ¿Ð¸Ñ Ð²Ñ–Ð´Ñутній" @@ -2717,6 +2741,10 @@ msgstr "" msgid "No result" msgstr "Результати відÑутні" +#: src/components/Lists.tsx:192 +msgid "No results found" +msgstr "" + #: src/view/screens/Feeds.tsx:495 msgid "No results found for \"{query}\"" msgstr "Ðічого не знайдено за запитом «{query}»" @@ -2748,7 +2776,7 @@ msgstr "Ðіхто" msgid "Not Applicable." msgstr "Ðе заÑтоÑовно." -#: src/Navigation.tsx:105 +#: src/Navigation.tsx:107 #: src/view/screens/Profile.tsx:106 msgid "Not Found" msgstr "" @@ -2770,7 +2798,7 @@ msgstr "Примітка: Bluesky Ñ” відкритою Ñ– публічною м #~ msgid "Note: Third-party apps that display Bluesky content may not respect this setting." #~ msgstr "" -#: src/Navigation.tsx:450 +#: src/Navigation.tsx:457 #: src/view/screens/Notifications.tsx:124 #: src/view/screens/Notifications.tsx:148 #: src/view/shell/bottom-bar/BottomBar.tsx:205 @@ -2812,6 +2840,11 @@ msgstr "Ð”Ð»Ñ Ð¾Ð´Ð½Ð¾Ð³Ð¾ або кількох зображень відÑÑƒÑ msgid "Only {0} can reply." msgstr "Тільки {0} можуть відповідати." +#: src/components/Lists.tsx:82 +msgid "Oops, something went wrong!" +msgstr "" + +#: src/components/Lists.tsx:188 #: src/view/screens/AppPasswords.tsx:65 #: src/view/screens/Profile.tsx:106 msgid "Oops!" @@ -2838,10 +2871,14 @@ msgstr "" msgid "Open muted words settings" msgstr "" -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:49 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:50 msgid "Open navigation" msgstr "Відкрити навігацію" +#: src/view/com/util/forms/PostDropdownBtn.tsx:175 +msgid "Open post options menu" +msgstr "" + #: src/view/screens/Settings/index.tsx:804 msgid "Open storybook page" msgstr "" @@ -2854,7 +2891,7 @@ msgstr "" msgid "Opens additional details for a debug entry" msgstr "" -#: src/view/com/notifications/FeedItem.tsx:348 +#: src/view/com/notifications/FeedItem.tsx:349 msgid "Opens an expanded list of users in this notification" msgstr "" @@ -2914,7 +2951,7 @@ msgstr "Відкриває Ð½Ð°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¼Ð¾Ð´ÐµÑ€Ð°Ñ†Ñ–Ñ—" msgid "Opens password reset form" msgstr "" -#: src/view/com/home/HomeHeaderLayout.web.tsx:60 +#: src/view/com/home/HomeHeaderLayout.web.tsx:63 #: src/view/screens/Feeds.tsx:356 msgid "Opens screen to edit Saved Feeds" msgstr "" @@ -2967,6 +3004,7 @@ msgstr "Інший обліковий запиÑ" msgid "Other..." msgstr "Інші..." +#: src/components/Lists.tsx:194 #: src/view/screens/NotFound.tsx:45 msgid "Page not found" msgstr "Сторінку не знайдено" @@ -2975,8 +3013,8 @@ msgstr "Сторінку не знайдено" msgid "Page Not Found" msgstr "" -#: src/view/com/auth/create/Step1.tsx:214 -#: src/view/com/auth/create/Step1.tsx:224 +#: src/view/com/auth/create/Step1.tsx:191 +#: src/view/com/auth/create/Step1.tsx:201 #: src/view/com/auth/login/LoginForm.tsx:226 #: src/view/com/auth/login/SetNewPasswordForm.tsx:161 #: src/view/com/modals/DeleteAccount.tsx:202 @@ -2991,11 +3029,11 @@ msgstr "Пароль змінено" msgid "Password updated!" msgstr "Пароль змінено!" -#: src/Navigation.tsx:160 +#: src/Navigation.tsx:162 msgid "People followed by @{0}" msgstr "" -#: src/Navigation.tsx:153 +#: src/Navigation.tsx:155 msgid "People following @{0}" msgstr "" @@ -3069,6 +3107,10 @@ msgstr "" msgid "Please enter a unique name for this App Password or use our randomly generated one." msgstr "Будь лаÑка, введіть унікальну назву Ð´Ð»Ñ Ñ†ÑŒÐ¾Ð³Ð¾ паролю або викориÑтовуйте нашу випадково згенеровану." +#: src/components/dialogs/MutedWords.tsx:68 +msgid "Please enter a valid word, tag, or phrase to mute" +msgstr "" + #: src/view/com/auth/create/state.ts:170 #~ msgid "Please enter the code you received by SMS." #~ msgstr "" @@ -3132,13 +3174,13 @@ msgstr "" msgid "Post by {0}" msgstr "" -#: src/Navigation.tsx:172 -#: src/Navigation.tsx:179 -#: src/Navigation.tsx:186 +#: src/Navigation.tsx:174 +#: src/Navigation.tsx:181 +#: src/Navigation.tsx:188 msgid "Post by @{0}" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:90 +#: src/view/com/util/forms/PostDropdownBtn.tsx:108 msgid "Post deleted" msgstr "" @@ -3158,7 +3200,7 @@ msgstr "Мови поÑту" msgid "Post not found" msgstr "ПоÑÑ‚ не знайдено" -#: src/components/TagMenu/index.tsx:257 +#: src/components/TagMenu/index.tsx:253 msgid "posts" msgstr "" @@ -3166,7 +3208,7 @@ msgstr "" msgid "Posts" msgstr "ПоÑти" -#: src/components/dialogs/MutedWords.tsx:77 +#: src/components/dialogs/MutedWords.tsx:90 msgid "Posts can be muted based on their text, their tags, or both." msgstr "" @@ -3195,7 +3237,7 @@ msgstr "Пріоритезувати ваші підпиÑки" msgid "Privacy" msgstr "КонфіденційніÑть" -#: src/Navigation.tsx:217 +#: src/Navigation.tsx:219 #: src/view/screens/PrivacyPolicy.tsx:29 #: src/view/screens/Settings/index.tsx:891 #: src/view/shell/Drawer.tsx:262 @@ -3281,7 +3323,7 @@ msgstr "Рекомендовані Ñтрічки" msgid "Recommended Users" msgstr "Рекомендовані кориÑтувачі" -#: src/components/dialogs/MutedWords.tsx:249 +#: src/components/dialogs/MutedWords.tsx:298 #: src/view/com/modals/ListAddRemoveUsers.tsx:264 #: src/view/com/modals/SelfLabel.tsx:83 #: src/view/com/modals/UserAddRemoveLists.tsx:219 @@ -3319,7 +3361,7 @@ msgstr "Вилучити зображеннÑ" msgid "Remove image preview" msgstr "Вилучити попередній переглÑд зображеннÑ" -#: src/components/dialogs/MutedWords.tsx:294 +#: src/components/dialogs/MutedWords.tsx:343 msgid "Remove mute word from your list" msgstr "" @@ -3389,7 +3431,8 @@ msgid "Report List" msgstr "ПоÑкаржитиÑÑŒ на ÑпиÑок" #: src/view/com/modals/report/SendReportButton.tsx:37 -#: src/view/com/util/forms/PostDropdownBtn.tsx:255 +#: src/view/com/util/forms/PostDropdownBtn.tsx:301 +#: src/view/com/util/forms/PostDropdownBtn.tsx:309 msgid "Report post" msgstr "ПоÑкаржитиÑÑŒ на поÑÑ‚" @@ -3460,7 +3503,7 @@ msgstr "" msgid "Require alt text before posting" msgstr "Вимагати альтернативний текÑÑ‚ до зображень перед публікацією" -#: src/view/com/auth/create/Step1.tsx:153 +#: src/view/com/auth/create/Step1.tsx:146 msgid "Required for this provider" msgstr "ВимагаєтьÑÑ Ñ†Ð¸Ð¼ хоÑтинг-провайдером" @@ -3529,7 +3572,7 @@ msgstr "Повторити Ñпробу" #~ msgid "Retry." #~ msgstr "" -#: src/view/screens/ProfileList.tsx:898 +#: src/view/screens/ProfileList.tsx:903 msgid "Return to previous page" msgstr "" @@ -3588,11 +3631,11 @@ msgstr "" msgid "Science" msgstr "" -#: src/view/screens/ProfileList.tsx:854 +#: src/view/screens/ProfileList.tsx:859 msgid "Scroll to top" msgstr "" -#: src/Navigation.tsx:440 +#: src/Navigation.tsx:447 #: src/view/com/auth/LoggedOut.tsx:122 #: src/view/com/modals/ListAddRemoveUsers.tsx:75 #: src/view/com/util/forms/SearchInput.tsx:67 @@ -3615,13 +3658,21 @@ msgid "Search for \"{query}\"" msgstr "" #: src/components/TagMenu/index.tsx:145 -msgid "Search for all posts by @{authorHandle} with tag {tag}" +msgid "Search for all posts by @{authorHandle} with tag {displayTag}" msgstr "" -#: src/components/TagMenu/index.tsx:90 -msgid "Search for all posts with tag {tag}" +#: src/components/TagMenu/index.tsx:145 +#~ msgid "Search for all posts by @{authorHandle} with tag {tag}" +#~ msgstr "" + +#: src/components/TagMenu/index.tsx:94 +msgid "Search for all posts with tag {displayTag}" msgstr "" +#: src/components/TagMenu/index.tsx:90 +#~ msgid "Search for all posts with tag {tag}" +#~ msgstr "" + #: src/view/screens/Search/Search.tsx:390 #~ msgid "Search for posts and users." #~ msgstr "" @@ -3636,22 +3687,30 @@ msgstr "Пошук кориÑтувачів" msgid "Security Step Required" msgstr "Потрібен код підтвердженнÑ" -#: src/components/TagMenu/index.web.tsx:50 +#: src/components/TagMenu/index.web.tsx:66 msgid "See {truncatedTag} posts" msgstr "" -#: src/components/TagMenu/index.web.tsx:67 +#: src/components/TagMenu/index.web.tsx:83 msgid "See {truncatedTag} posts by user" msgstr "" #: src/components/TagMenu/index.tsx:128 -msgid "See <0>{tag}</0> posts" +msgid "See <0>{displayTag}</0> posts" msgstr "" -#: src/components/TagMenu/index.tsx:189 -msgid "See <0>{tag}</0> posts by this user" +#: src/components/TagMenu/index.tsx:187 +msgid "See <0>{displayTag}</0> posts by this user" msgstr "" +#: src/components/TagMenu/index.tsx:128 +#~ msgid "See <0>{tag}</0> posts" +#~ msgstr "" + +#: src/components/TagMenu/index.tsx:189 +#~ msgid "See <0>{tag}</0> posts by this user" +#~ msgstr "" + #: src/view/screens/SavedFeeds.tsx:163 msgid "See this guide" msgstr "" @@ -3676,7 +3735,7 @@ msgstr "Вибрати Ñ–Ñнуючий обліковий запиÑ" msgid "Select option {i} of {numItems}" msgstr "" -#: src/view/com/auth/create/Step1.tsx:103 +#: src/view/com/auth/create/Step1.tsx:96 #: src/view/com/auth/login/LoginForm.tsx:150 msgid "Select service" msgstr "Вибрати хоÑтинг-провайдера" @@ -3798,7 +3857,7 @@ msgstr "" msgid "Set new password" msgstr "Зміна паролÑ" -#: src/view/com/auth/create/Step1.tsx:225 +#: src/view/com/auth/create/Step1.tsx:202 msgid "Set password" msgstr "" @@ -3846,12 +3905,12 @@ msgstr "" #~ msgid "Sets hosting provider to {label}" #~ msgstr "" -#: src/view/com/auth/create/Step1.tsx:104 +#: src/view/com/auth/create/Step1.tsx:97 #: src/view/com/auth/login/LoginForm.tsx:151 msgid "Sets server for the Bluesky client" msgstr "" -#: src/Navigation.tsx:135 +#: src/Navigation.tsx:137 #: src/view/screens/Settings/index.tsx:294 #: src/view/shell/desktop/LeftNav.tsx:433 #: src/view/shell/Drawer.tsx:567 @@ -3869,7 +3928,9 @@ msgid "Share" msgstr "" #: src/view/com/profile/ProfileHeader.tsx:295 -#: src/view/com/util/forms/PostDropdownBtn.tsx:184 +#: src/view/com/util/forms/PostDropdownBtn.tsx:231 +#: src/view/com/util/forms/PostDropdownBtn.tsx:237 +#: src/view/com/util/post-ctrls/PostCtrls.tsx:215 #: src/view/screens/ProfileList.tsx:418 msgid "Share" msgstr "Поширити" @@ -3965,7 +4026,7 @@ msgstr "" msgid "Show the content" msgstr "" -#: src/view/com/notifications/FeedItem.tsx:346 +#: src/view/com/notifications/FeedItem.tsx:347 msgid "Show users" msgstr "Показати кориÑтувачів" @@ -4072,11 +4133,15 @@ msgstr "" #~ msgid "Something went wrong and we're not sure what." #~ msgstr "" -#: src/view/com/modals/Waitlist.tsx:51 -msgid "Something went wrong. Check your email and try again." +#: src/components/Lists.tsx:203 +msgid "Something went wrong!" msgstr "" -#: src/App.native.tsx:63 +#: src/view/com/modals/Waitlist.tsx:51 +#~ msgid "Something went wrong. Check your email and try again." +#~ msgstr "" + +#: src/App.native.tsx:66 msgid "Sorry! Your session expired. Please log in again." msgstr "" @@ -4116,7 +4181,7 @@ msgstr "" msgid "Storage cleared, you need to restart the app now." msgstr "" -#: src/Navigation.tsx:202 +#: src/Navigation.tsx:204 #: src/view/screens/Settings/index.tsx:807 msgid "Storybook" msgstr "" @@ -4130,7 +4195,7 @@ msgid "Subscribe" msgstr "ПідпиÑатиÑÑ" #: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:173 -#: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:307 +#: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:308 msgid "Subscribe to the {0} feed" msgstr "" @@ -4154,7 +4219,7 @@ msgstr "" msgid "Suggestive" msgstr "" -#: src/Navigation.tsx:212 +#: src/Navigation.tsx:214 #: src/view/screens/Support.tsx:30 #: src/view/screens/Support.tsx:33 msgid "Support" @@ -4186,14 +4251,18 @@ msgstr "" msgid "System log" msgstr "СиÑтемний журнал" -#: src/components/dialogs/MutedWords.tsx:288 +#: src/components/dialogs/MutedWords.tsx:337 msgid "tag" msgstr "" -#: src/components/TagMenu/index.tsx:74 -msgid "Tag menu: {tag}" +#: src/components/TagMenu/index.tsx:78 +msgid "Tag menu: {displayTag}" msgstr "" +#: src/components/TagMenu/index.tsx:74 +#~ msgid "Tag menu: {tag}" +#~ msgstr "" + #: src/view/com/modals/crop-image/CropImage.web.tsx:112 msgid "Tall" msgstr "ВиÑоке" @@ -4210,14 +4279,14 @@ msgstr "" msgid "Terms" msgstr "Умови" -#: src/Navigation.tsx:222 +#: src/Navigation.tsx:224 #: src/view/screens/Settings/index.tsx:885 #: src/view/screens/TermsOfService.tsx:29 #: src/view/shell/Drawer.tsx:256 msgid "Terms of Service" msgstr "Умови ВикориÑтаннÑ" -#: src/components/dialogs/MutedWords.tsx:288 +#: src/components/dialogs/MutedWords.tsx:337 msgid "text" msgstr "" @@ -4302,7 +4371,7 @@ msgstr "" msgid "There was an issue fetching notifications. Tap here to try again." msgstr "" -#: src/view/com/posts/Feed.tsx:263 +#: src/view/com/posts/Feed.tsx:265 msgid "There was an issue fetching posts. Tap here to try again." msgstr "" @@ -4420,7 +4489,7 @@ msgstr "Це важливо Ð´Ð»Ñ Ð²Ð¸Ð¿Ð°Ð´ÐºÑƒ, Ñкщо вам коли-не msgid "This link is taking you to the following website:" msgstr "Це поÑÐ¸Ð»Ð°Ð½Ð½Ñ Ð²ÐµÐ´Ðµ на Ñайт:" -#: src/view/screens/ProfileList.tsx:834 +#: src/view/screens/ProfileList.tsx:839 msgid "This list is empty!" msgstr "" @@ -4452,11 +4521,11 @@ msgstr "" msgid "This warning is only available for posts with media attached." msgstr "Це Ð¿Ð¾Ð¿ÐµÑ€ÐµÐ´Ð¶ÐµÐ½Ð½Ñ Ð´Ð¾Ñтупне тільки Ð´Ð»Ñ Ð·Ð°Ð¿Ð¸Ñів з прикріпленими медіа-файлами." -#: src/components/dialogs/MutedWords.tsx:236 +#: src/components/dialogs/MutedWords.tsx:285 msgid "This will delete {0} from your muted words. You can always add it back later." msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:237 +#: src/view/com/util/forms/PostDropdownBtn.tsx:282 msgid "This will hide this post from your feeds." msgstr "Це приховає цей поÑÑ‚ із вашої Ñтрічки." @@ -4469,11 +4538,11 @@ msgstr "ÐÐ°Ð»Ð°ÑˆÑ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð³Ñ–Ð»Ð¾Ðº" msgid "Threaded Mode" msgstr "Режим гілок" -#: src/Navigation.tsx:255 +#: src/Navigation.tsx:257 msgid "Threads Preferences" msgstr "" -#: src/components/dialogs/MutedWords.tsx:95 +#: src/components/dialogs/MutedWords.tsx:113 msgid "Toggle between muted word options." msgstr "" @@ -4487,7 +4556,8 @@ msgstr "РедагуваннÑ" #: src/view/com/post-thread/PostThreadItem.tsx:685 #: src/view/com/post-thread/PostThreadItem.tsx:687 -#: src/view/com/util/forms/PostDropdownBtn.tsx:156 +#: src/view/com/util/forms/PostDropdownBtn.tsx:215 +#: src/view/com/util/forms/PostDropdownBtn.tsx:217 msgid "Translate" msgstr "ПереклаÑти" @@ -4552,16 +4622,15 @@ msgid "Unfortunately, you do not meet the requirements to create an account." msgstr "Ðа жаль, ви не відповідаєте вимогам Ð´Ð»Ñ ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¾Ð±Ð»Ñ–ÐºÐ¾Ð²Ð¾Ð³Ð¾ запиÑу." #: src/view/com/util/post-ctrls/PostCtrls.tsx:182 -#: src/view/com/util/post-ctrls/PostCtrls.tsx:216 msgid "Unlike" msgstr "" -#: src/components/TagMenu/index.tsx:253 +#: src/components/TagMenu/index.tsx:249 #: src/view/screens/ProfileList.tsx:597 msgid "Unmute" msgstr "" -#: src/components/TagMenu/index.web.tsx:90 +#: src/components/TagMenu/index.web.tsx:104 msgid "Unmute {truncatedTag}" msgstr "" @@ -4569,11 +4638,16 @@ msgstr "" msgid "Unmute Account" msgstr "ПереÑтати ігнорувати" -#: src/components/TagMenu/index.tsx:210 -msgid "Unmute all {tag} posts" +#: src/components/TagMenu/index.tsx:208 +msgid "Unmute all {displayTag} posts" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:202 +#: src/components/TagMenu/index.tsx:210 +#~ msgid "Unmute all {tag} posts" +#~ msgstr "" + +#: src/view/com/util/forms/PostDropdownBtn.tsx:251 +#: src/view/com/util/forms/PostDropdownBtn.tsx:256 msgid "Unmute thread" msgstr "ПереÑтати ігнорувати" @@ -4657,13 +4731,13 @@ msgstr "ПÑевдонім" msgid "User list by {0}" msgstr "" -#: src/view/screens/ProfileList.tsx:762 +#: src/view/screens/ProfileList.tsx:763 msgid "User list by <0/>" msgstr "" #: src/view/com/lists/ListCard.tsx:83 #: src/view/com/modals/UserAddRemoveLists.tsx:196 -#: src/view/screens/ProfileList.tsx:760 +#: src/view/screens/ProfileList.tsx:761 msgid "User list by you" msgstr "" @@ -4684,7 +4758,7 @@ msgstr "СпиÑки кориÑтувачів" msgid "Username or email address" msgstr "Ім'Ñ ÐºÐ¾Ñ€Ð¸Ñтувача або електронна адреÑа" -#: src/view/screens/ProfileList.tsx:796 +#: src/view/screens/ProfileList.tsx:797 msgid "Users" msgstr "КориÑтувачі" @@ -4762,6 +4836,10 @@ msgstr "" msgid "We also think you'll like \"For You\" by Skygaze:" msgstr "" +#: src/screens/Hashtag.tsx:132 +msgid "We couldn't find any results for that hashtag." +msgstr "" + #: src/screens/Deactivated.tsx:133 msgid "We estimate {estimatedTime} until your account is ready." msgstr "" @@ -4782,7 +4860,7 @@ msgstr "" #~ msgid "We recommend \"For You\" by Skygaze:" #~ msgstr "" -#: src/components/dialogs/MutedWords.tsx:161 +#: src/components/dialogs/MutedWords.tsx:204 msgid "We recommend avoiding common words that appear in many posts, since it can result in no posts being shown." msgstr "" @@ -4822,7 +4900,7 @@ msgstr "Ми дуже раді, що ви приєдналиÑÑ!" msgid "We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @{handleOrDid}." msgstr "" -#: src/components/dialogs/MutedWords.tsx:182 +#: src/components/dialogs/MutedWords.tsx:230 msgid "We're sorry, but we weren't able to load your muted words at this time. Please try again." msgstr "" @@ -4830,6 +4908,7 @@ msgstr "" msgid "We're sorry, but your search could not be completed. Please try again in a few minutes." msgstr "Даруйте, нам не вдалоÑÑ Ð²Ð¸ÐºÐ¾Ð½Ð°Ñ‚Ð¸ пошук за вашим запитом. Будь лаÑка, Ñпробуйте ще раз через кілька хвилин." +#: src/components/Lists.tsx:211 #: src/view/screens/NotFound.tsx:48 msgid "We're sorry! We can't find the page you were looking for." msgstr "Ðам дуже прикро! Ми не можемо знайти Ñторінку, Ñку ви шукали." @@ -4985,7 +5064,7 @@ msgstr "Ви ще не Ñтворили жодного Ð¿Ð°Ñ€Ð¾Ð»Ñ Ð´Ð»Ñ Ð·Ð°Ñ msgid "You have not muted any accounts yet. To mute an account, go to their profile and selected \"Mute account\" from the menu on their account." msgstr "Ви ще не ігноруєте жодного облікового запиÑу. Щоб ігнорувати когоÑÑŒ, перейдіть до Ñ—Ñ… профілю та виберіть опцію \"Ігнорувати\" у меню Ñ—Ñ… облікового запиÑу." -#: src/components/dialogs/MutedWords.tsx:202 +#: src/components/dialogs/MutedWords.tsx:250 msgid "You haven't muted any words or tags yet" msgstr "" @@ -4997,11 +5076,11 @@ msgstr "" msgid "You must be 18 years or older to enable adult content" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:129 +#: src/view/com/util/forms/PostDropdownBtn.tsx:147 msgid "You will no longer receive notifications for this thread" msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:132 +#: src/view/com/util/forms/PostDropdownBtn.tsx:150 msgid "You will now receive notifications for this thread" msgstr "" @@ -5027,7 +5106,7 @@ msgstr "" msgid "You've reached the end of your feed! Find some more accounts to follow." msgstr "" -#: src/view/com/auth/create/Step1.tsx:74 +#: src/view/com/auth/create/Step1.tsx:67 msgid "Your account" msgstr "Ваш акаунт" @@ -5039,7 +5118,7 @@ msgstr "" msgid "Your account repository, containing all public data records, can be downloaded as a \"CAR\" file. This file does not include media embeds, such as images, or your private data, which must be fetched separately." msgstr "" -#: src/view/com/auth/create/Step1.tsx:238 +#: src/view/com/auth/create/Step1.tsx:215 msgid "Your birth date" msgstr "Ваша дата народженнÑ" @@ -5058,8 +5137,8 @@ msgid "Your email appears to be invalid." msgstr "Ðе вдалоÑÑ Ñ€Ð¾Ð·Ð¿Ñ–Ð·Ð½Ð°Ñ‚Ð¸ адреÑу електронної пошти." #: src/view/com/modals/Waitlist.tsx:109 -msgid "Your email has been saved! We'll be in touch soon." -msgstr "Вашу електронну адреÑу збережено! Ми Ñкоро зв'ÑжемоÑÑ Ð· вами." +#~ msgid "Your email has been saved! We'll be in touch soon." +#~ msgstr "Вашу електронну адреÑу збережено! Ми Ñкоро зв'ÑжемоÑÑ Ð· вами." #: src/view/com/modals/ChangeEmail.tsx:125 msgid "Your email has been updated but not verified. As a next step, please verify your new email." @@ -5091,7 +5170,7 @@ msgstr "" #~ msgid "Your invite codes are hidden when logged in using an App Password" #~ msgstr "Ваші коди Ð·Ð°Ð¿Ñ€Ð¾ÑˆÐµÐ½Ð½Ñ Ð¿Ñ€Ð¸Ñ…Ð¾Ð²Ð°Ð½Ð¾, Ñкщо ви увійшли за допомогою Ð¿Ð°Ñ€Ð¾Ð»Ñ Ð´Ð»Ñ Ð·Ð°ÑтоÑунків" -#: src/components/dialogs/MutedWords.tsx:173 +#: src/components/dialogs/MutedWords.tsx:221 msgid "Your muted words" msgstr "" diff --git a/src/locale/locales/zh-CN/messages.po b/src/locale/locales/zh-CN/messages.po index c4447af26..d7fb15b03 100644 --- a/src/locale/locales/zh-CN/messages.po +++ b/src/locale/locales/zh-CN/messages.po @@ -1,6 +1,6 @@ msgid "" msgstr "" -"POT-Creation-Date: 2024-02-07 19:20+0800\n" +"POT-Creation-Date: 2024-02-17 21:00+0800\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" @@ -23,7 +23,7 @@ msgstr "(没有邮件)" #: src/view/com/profile/ProfileHeader.tsx:593 msgid "{following} following" -msgstr "{following} æ£åœ¨å…³æ³¨" +msgstr "{following} 个æ£åœ¨å…³æ³¨" #: src/view/shell/desktop/RightNav.tsx:151 #~ msgid "{invitesAvailable, plural, one {Invite codes: # available} other {Invite codes: # available}}" @@ -41,15 +41,15 @@ msgstr "{following} æ£åœ¨å…³æ³¨" #: src/view/shell/Drawer.tsx:440 msgid "{numUnreadNotifications} unread" -msgstr "{numUnreadNotifications} 未读" +msgstr "{numUnreadNotifications} 个未读" #: src/view/com/threadgate/WhoCanReply.tsx:158 msgid "<0/> members" -msgstr "<0/> æˆå‘˜" +msgstr "<0/> 个æˆå‘˜" #: src/view/com/profile/ProfileHeader.tsx:595 msgid "<0>{following} </0><1>following</1>" -msgstr "<0>{following} </0><1>æ£åœ¨å…³æ³¨</1>" +msgstr "<0>{following} </0><1>个æ£åœ¨å…³æ³¨</1>" #: src/view/com/auth/onboarding/RecommendedFeeds.tsx:30 msgid "<0>Choose your</0><1>Recommended</1><2>Feeds</2>" @@ -69,18 +69,18 @@ msgstr "âš æ— æ•ˆçš„ç”¨æˆ·è¯†åˆ«ç¬¦" #: src/view/com/util/moderation/LabelInfo.tsx:45 msgid "A content warning has been applied to this {0}." -msgstr "æ¤å¤„å·²å¯ç”¨å†…容è¦å‘Š {0}." +msgstr "内容è¦å‘Šå·²å¥—用到这个{0}." #: src/lib/hooks/useOTAUpdate.ts:16 msgid "A new version of the app is available. Please update to continue using the app." -msgstr "App 新版本已å‘布,请更新以继ç»ä½¿ç”¨ã€‚" +msgstr "应用新版本已å‘布,请更新以继ç»ä½¿ç”¨ã€‚" -#: src/view/com/util/ViewHeader.tsx:83 +#: src/view/com/util/ViewHeader.tsx:89 #: src/view/screens/Search/Search.tsx:647 msgid "Access navigation links and settings" msgstr "访问导航链接åŠè®¾ç½®" -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:51 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:52 msgid "Access profile and other navigation links" msgstr "访问个人资料åŠå…¶ä»–导航链接" @@ -127,19 +127,19 @@ msgstr "已喿¶ˆå±è”½è´¦æˆ·" msgid "Account unmuted" msgstr "已喿¶ˆéšè—账户" -#: src/components/dialogs/MutedWords.tsx:147 +#: src/components/dialogs/MutedWords.tsx:165 #: src/view/com/auth/onboarding/RecommendedFeedsItem.tsx:150 #: src/view/com/modals/ListAddRemoveUsers.tsx:264 #: src/view/com/modals/UserAddRemoveLists.tsx:219 -#: src/view/screens/ProfileList.tsx:812 +#: src/view/screens/ProfileList.tsx:813 msgid "Add" msgstr "æ·»åŠ " #: src/view/com/modals/SelfLabel.tsx:56 msgid "Add a content warning" -msgstr "æ·»åŠ å†…å®¹è¦å‘Š" +msgstr "新增内容è¦å‘Š" -#: src/view/screens/ProfileList.tsx:802 +#: src/view/screens/ProfileList.tsx:803 msgid "Add a user to this list" msgstr "å°†ç”¨æˆ·æ·»åŠ è‡³åˆ—è¡¨" @@ -152,18 +152,18 @@ msgstr "æ·»åŠ è´¦æˆ·" #: src/view/com/composer/photos/Gallery.tsx:180 #: src/view/com/modals/AltImage.tsx:116 msgid "Add alt text" -msgstr "æ·»åŠ æ›¿ä»£æ–‡å—" +msgstr "新增替代文å—" #: src/view/screens/AppPasswords.tsx:102 #: src/view/screens/AppPasswords.tsx:143 #: src/view/screens/AppPasswords.tsx:156 msgid "Add App Password" -msgstr "æ·»åŠ App 专用密ç " +msgstr "新增应用专用密ç " #: src/view/com/modals/report/InputIssueDetails.tsx:41 #: src/view/com/modals/report/Modal.tsx:191 msgid "Add details" -msgstr "æ·»åŠ ç»†èŠ‚" +msgstr "新增细节" #: src/view/com/modals/report/Modal.tsx:194 msgid "Add details to report" @@ -177,17 +177,17 @@ msgstr "æ·»åŠ é“¾æŽ¥å¡ç‰‡" msgid "Add link card:" msgstr "æ·»åŠ é“¾æŽ¥å¡ç‰‡:" -#: src/components/dialogs/MutedWords.tsx:140 +#: src/components/dialogs/MutedWords.tsx:158 msgid "Add mute word for configured settings" -msgstr "" +msgstr "为é…ç½®çš„è®¾ç½®æ·»åŠ éšè—è¯" -#: src/components/dialogs/MutedWords.tsx:74 +#: src/components/dialogs/MutedWords.tsx:87 msgid "Add muted words and tags" -msgstr "" +msgstr "æ·»åŠ éšè—è¯å’Œè¯é¢˜æ ‡ç¾" #: src/view/com/modals/ChangeHandle.tsx:417 msgid "Add the following DNS record to your domain:" -msgstr "将以下DNSè®°å½•æ·»åŠ åˆ°ä½ çš„åŸŸå:" +msgstr "将以下 DNS è®°å½•æ–°å¢žåˆ°ä½ çš„åŸŸå:" #: src/view/com/profile/ProfileHeader.tsx:310 msgid "Add to Lists" @@ -205,15 +205,15 @@ msgstr "å·²æ·»åŠ " #: src/view/com/modals/ListAddRemoveUsers.tsx:191 #: src/view/com/modals/UserAddRemoveLists.tsx:144 msgid "Added to list" -msgstr "æ·»åŠ è‡³åˆ—è¡¨" +msgstr "å·²æ·»åŠ è‡³åˆ—è¡¨" #: src/view/com/feeds/FeedSourceCard.tsx:127 msgid "Added to my feeds" -msgstr "æ·»åŠ è‡³è‡ªå®šä¹‰ä¿¡æ¯æµ" +msgstr "å·²æ·»åŠ è‡³è‡ªå®šä¹‰ä¿¡æ¯æµ" #: src/view/screens/PreferencesFollowingFeed.tsx:173 msgid "Adjust the number of likes a reply must have to be shown in your feed." -msgstr "调整回å¤ä¸éœ€è¦å…·æœ‰çš„点赞数æ‰ä¼šåœ¨ä½ çš„ä¿¡æ¯æµä¸æ˜¾ç¤ºã€‚" +msgstr "调整回å¤ä¸éœ€è¦å…·æœ‰çš„喜欢数æ‰ä¼šåœ¨ä½ çš„ä¿¡æ¯æµä¸æ˜¾ç¤ºã€‚" #: src/view/com/modals/SelfLabel.tsx:75 msgid "Adult Content" @@ -221,7 +221,7 @@ msgstr "æˆäººå†…容" #: src/view/com/modals/ContentFilteringSettings.tsx:141 msgid "Adult content can only be enabled via the Web at <0/>." -msgstr "è¦æ˜¾ç¤ºæˆäººå†…å®¹ï¼Œä½ å¿…é¡»è®¿é—®ç½‘é¡µç«¯ä¸Šçš„<0/>。" +msgstr "è¦æ˜¾ç¤ºæˆäººå†…å®¹ï¼Œä½ å¿…é¡»è®¿é—®ç½‘é¡µç«¯<0/>æ¥å¯ç”¨ã€‚" #: src/view/screens/Settings/index.tsx:664 msgid "Advanced" @@ -229,12 +229,12 @@ msgstr "详细设置" #: src/view/screens/Feeds.tsx:666 msgid "All the feeds you've saved, right in one place." -msgstr "" +msgstr "ä½ ä¿å˜çš„æ‰€æœ‰ä¿¡æ¯æµéƒ½é›†ä¸åœ¨ä¸€å¤„。" #: src/view/com/auth/login/ForgotPasswordForm.tsx:221 #: src/view/com/modals/ChangePassword.tsx:168 msgid "Already have a code?" -msgstr "å·²ç»æœ‰ç¡®è®¤ç 了?" +msgstr "å·²ç»æœ‰éªŒè¯ç 了?" #: src/view/com/auth/login/ChooseAccountForm.tsx:98 msgid "Already signed in as @{0}" @@ -250,7 +250,7 @@ msgstr "替代文å—" #: src/view/com/composer/photos/Gallery.tsx:209 msgid "Alt text describes images for blind and low-vision users, and helps give context to everyone." -msgstr "ä¸ºå›¾ç‰‡æ·»åŠ æ›¿ä»£æ–‡å—,以帮助盲人åŠè§†éšœç¾¤ä½“了解图片内容。" +msgstr "为图片新增替代文å—,以帮助盲人åŠè§†éšœç¾¤ä½“了解图片内容。" #: src/view/com/modals/VerifyEmail.tsx:124 msgid "An email has been sent to {0}. It includes a confirmation code which you can enter below." @@ -265,7 +265,7 @@ msgstr "一å°ç”µå邮件已å‘é€è‡³å…ˆå‰å¡«å†™çš„邮箱 {0}ã€‚è¯·æŸ¥é˜…é‚®ä» msgid "An issue occurred, please try again." msgstr "出现问题,请é‡è¯•。" -#: src/view/com/notifications/FeedItem.tsx:236 +#: src/view/com/notifications/FeedItem.tsx:237 #: src/view/com/threadgate/WhoCanReply.tsx:178 msgid "and" msgstr "å’Œ" @@ -280,31 +280,32 @@ msgstr "应用è¯è¨€" #: src/view/screens/AppPasswords.tsx:228 msgid "App password deleted" -msgstr "App 专用密ç å·²åˆ é™¤" +msgstr "应用专用密ç å·²åˆ é™¤" #: src/view/com/modals/AddAppPasswords.tsx:134 msgid "App Password names can only contain letters, numbers, spaces, dashes, and underscores." -msgstr "App 专用密ç åªèƒ½åŒ…å«å—æ¯ã€æ•°å—ã€ç©ºæ ¼ã€ç ´æŠ˜å·åŠä¸‹åˆ’线。" +msgstr "应用专用密ç åªèƒ½åŒ…å«å—æ¯ã€æ•°å—ã€ç©ºæ ¼ã€ç ´æŠ˜å·åŠä¸‹åˆ’线。" #: src/view/com/modals/AddAppPasswords.tsx:99 msgid "App Password names must be at least 4 characters long." -msgstr "App 专用密ç 必须至少为 4 个å—符。" +msgstr "应用专用密ç 必须至少为 4 个å—符。" #: src/view/screens/Settings/index.tsx:675 msgid "App password settings" -msgstr "App 专用密ç 设置" +msgstr "应用专用密ç 设置" #: src/view/screens/Settings.tsx:650 #~ msgid "App passwords" -#~ msgstr "App 专用密ç " +#~ msgstr "应用专用密ç " -#: src/Navigation.tsx:237 +#: src/Navigation.tsx:239 #: src/view/screens/AppPasswords.tsx:187 #: src/view/screens/Settings/index.tsx:684 msgid "App Passwords" -msgstr "App 专用密ç " +msgstr "应用专用密ç " -#: src/view/com/util/forms/PostDropdownBtn.tsx:295 +#: src/view/com/util/forms/PostDropdownBtn.tsx:337 +#: src/view/com/util/forms/PostDropdownBtn.tsx:346 msgid "Appeal content warning" msgstr "申诉内容è¦å‘Š" @@ -326,18 +327,18 @@ msgstr "外观" #: src/view/screens/AppPasswords.tsx:224 msgid "Are you sure you want to delete the app password \"{name}\"?" -msgstr "ä½ ç¡®å®šè¦åˆ é™¤è¿™æ¡ App 专用密ç \"{name}\"?" +msgstr "ä½ ç¡®å®šè¦åˆ 除这æ¡åº”用专用密ç \"{name}\"?" #: src/view/com/composer/Composer.tsx:150 msgid "Are you sure you'd like to discard this draft?" msgstr "ä½ ç¡®å®šè¦ä¸¢å¼ƒæ¤è‰ç¨¿å—?" -#: src/components/dialogs/MutedWords.tsx:233 +#: src/components/dialogs/MutedWords.tsx:282 #: src/view/screens/ProfileList.tsx:365 msgid "Are you sure?" msgstr "ä½ ç¡®å®šå—?" -#: src/view/com/util/forms/PostDropdownBtn.tsx:278 +#: src/view/com/util/forms/PostDropdownBtn.tsx:322 msgid "Are you sure? This cannot be undone." msgstr "ä½ ç¡®å®šå—ï¼Ÿæ¤æ“ä½œæ— æ³•æ’¤é”€ã€‚" @@ -363,7 +364,7 @@ msgstr "è‰ºæœ¯ä½œå“æˆ–éžè‰²æƒ…的裸体。" #: src/view/com/post-thread/PostThread.tsx:522 #: src/view/com/post-thread/PostThread.tsx:530 #: src/view/com/profile/ProfileHeader.tsx:649 -#: src/view/com/util/ViewHeader.tsx:81 +#: src/view/com/util/ViewHeader.tsx:87 msgid "Back" msgstr "返回" @@ -380,14 +381,14 @@ msgstr "åŸºäºŽä½ å¯¹ {interestsText} 感兴趣" msgid "Basics" msgstr "基础信æ¯" -#: src/view/com/auth/create/Step1.tsx:250 +#: src/view/com/auth/create/Step1.tsx:227 #: src/view/com/modals/BirthDateSettings.tsx:73 msgid "Birthday" msgstr "生日" #: src/view/screens/Settings/index.tsx:340 msgid "Birthday:" -msgstr "生日:" +msgstr "生日:" #: src/view/com/profile/ProfileHeader.tsx:239 #: src/view/com/profile/ProfileHeader.tsx:346 @@ -419,7 +420,7 @@ msgstr "å·²å±è”½" msgid "Blocked accounts" msgstr "å·²å±è”½è´¦æˆ·" -#: src/Navigation.tsx:130 +#: src/Navigation.tsx:132 #: src/view/screens/ModerationBlockedAccounts.tsx:107 msgid "Blocked Accounts" msgstr "å·²å±è”½è´¦æˆ·" @@ -438,7 +439,7 @@ msgstr "å·²å±è”½å¸–å。" #: src/view/screens/ProfileList.tsx:318 msgid "Blocking is public. Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you." -msgstr "å±è”½æ˜¯å…¬å…±æ€§çš„。被å±è”½çš„è´¦æˆ·æ— æ³•åœ¨ä½ çš„å¸–åä¸å›žå¤ã€æåŠä½ 或以其他方å¼ä¸Žä½ 互动。" +msgstr "å±è”½æ˜¯å…¬å¼€çš„。被å±è”½çš„è´¦æˆ·æ— æ³•åœ¨ä½ çš„å¸–åä¸å›žå¤ã€æåŠä½ 或以其他方å¼ä¸Žä½ 互动。" #: src/view/com/auth/HomeLoggedOutCTA.tsx:93 #: src/view/com/auth/SplashScreen.web.tsx:133 @@ -453,7 +454,7 @@ msgstr "Bluesky" #: src/view/com/auth/server-input/index.tsx:150 msgid "Bluesky is an open network where you can choose your hosting provider. Custom hosting is now available in beta for developers." -msgstr "" +msgstr "Bluesky æ˜¯ä¸€ä¸ªå¼€æ”¾çš„å…¬å…±ç½‘ç»œï¼Œä½ å¯ä»¥é€‰æ‹©è‡ªå·±çš„æ‰˜ç®¡æä¾›å•†ã€‚现在,自定义托管现在已ç»è¿›å…¥å¼€å‘者测试阶段。" #: src/view/com/auth/onboarding/WelcomeDesktop.tsx:80 #: src/view/com/auth/onboarding/WelcomeMobile.tsx:80 @@ -471,8 +472,8 @@ msgid "Bluesky is public." msgstr "Bluesky 为公众而生。" #: src/view/com/modals/Waitlist.tsx:70 -msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon." -msgstr "Bluesky ä½¿ç”¨é‚€è¯·åˆ¶æ¥æ‰“é€ æ›´å¥åº·çš„社群环境。 å¦‚æžœä½ ä¸è®¤è¯†æ‹¥æœ‰é‚€è¯·ç çš„äººï¼Œä½ å¯ä»¥å…ˆå¡«å†™å¹¶æäº¤å€™è¡¥åˆ—è¡¨ï¼Œæˆ‘ä»¬ä¼šå°½å¿«å®¡æ ¸å¹¶å‘é€é‚€è¯·ç 。" +#~ msgid "Bluesky uses invites to build a healthier community. If you don't know anybody with an invite, you can sign up for the waitlist and we'll send one soon." +#~ msgstr "Bluesky ä½¿ç”¨é‚€è¯·åˆ¶æ¥æ‰“é€ æ›´å¥åº·çš„社群环境。 å¦‚æžœä½ ä¸è®¤è¯†æ‹¥æœ‰é‚€è¯·ç çš„äººï¼Œä½ å¯ä»¥å…ˆå¡«å†™å¹¶æäº¤å€™è¡¥åˆ—è¡¨ï¼Œæˆ‘ä»¬ä¼šå°½å¿«å®¡æ ¸å¹¶å‘é€é‚€è¯·ç 。" #: src/view/screens/Moderation.tsx:245 msgid "Bluesky will not show your profile and posts to logged-out users. Other apps may not honor this request. This does not make your account private." @@ -525,7 +526,7 @@ msgstr "相机" msgid "Can only contain letters, numbers, spaces, dashes, and underscores. Must be at least 4 characters long, but no more than 32 characters long." msgstr "åªèƒ½åŒ…å«å—æ¯ã€æ•°å—ã€ç©ºæ ¼ã€ç ´æŠ˜å·åŠä¸‹åˆ’线。 长度必须至少 4 个å—符,但ä¸è¶…过 32 个å—符。" -#: src/components/Prompt.tsx:91 +#: src/components/Prompt.tsx:101 #: src/view/com/composer/Composer.tsx:307 #: src/view/com/composer/Composer.tsx:312 #: src/view/com/modals/ChangeEmail.tsx:218 @@ -540,7 +541,6 @@ msgstr "åªèƒ½åŒ…å«å—æ¯ã€æ•°å—ã€ç©ºæ ¼ã€ç ´æŠ˜å·åŠä¸‹åˆ’线。 é•¿åº¦å¿ #: src/view/com/modals/Repost.tsx:87 #: src/view/com/modals/VerifyEmail.tsx:247 #: src/view/com/modals/VerifyEmail.tsx:253 -#: src/view/com/modals/Waitlist.tsx:142 #: src/view/screens/Search/Search.tsx:716 #: src/view/shell/desktop/Search.tsx:238 msgid "Cancel" @@ -558,32 +558,32 @@ msgstr "å–æ¶ˆ" #: src/view/com/modals/DeleteAccount.tsx:152 #: src/view/com/modals/DeleteAccount.tsx:230 msgid "Cancel account deletion" -msgstr "æ’¤é”€è´¦æˆ·åˆ é™¤ç”³è¯·" +msgstr "å–æ¶ˆè´¦æˆ·åˆ 除申请" #: src/view/com/modals/ChangeHandle.tsx:149 msgid "Cancel change handle" -msgstr "撤销修改用户识别符" +msgstr "å–æ¶ˆä¿®æ”¹ç”¨æˆ·è¯†åˆ«ç¬¦" #: src/view/com/modals/crop-image/CropImage.web.tsx:134 msgid "Cancel image crop" -msgstr "撤销图片è£å‰ª" +msgstr "å–æ¶ˆè£å‰ªå›¾ç‰‡" #: src/view/com/modals/EditProfile.tsx:244 msgid "Cancel profile editing" -msgstr "撤销个人资料编辑" +msgstr "å–æ¶ˆç¼–辑个人资料" #: src/view/com/modals/Repost.tsx:78 msgid "Cancel quote post" -msgstr "撤销引用帖å" +msgstr "å–æ¶ˆå¼•用帖å" #: src/view/com/modals/ListAddRemoveUsers.tsx:87 #: src/view/shell/desktop/Search.tsx:234 msgid "Cancel search" -msgstr "撤销æœç´¢" +msgstr "å–æ¶ˆæœç´¢" #: src/view/com/modals/Waitlist.tsx:136 msgid "Cancel waitlist signup" -msgstr "撤销候补列表申请" +msgstr "å–æ¶ˆå€™è¡¥åˆ—表申请" #: src/view/screens/Settings/index.tsx:334 msgctxt "action" @@ -630,7 +630,7 @@ msgstr "检查我的状æ€" #: src/view/com/auth/onboarding/RecommendedFeeds.tsx:121 msgid "Check out some recommended feeds. Tap + to add them to your list of pinned feeds." -msgstr "查看一些推èçš„ä¿¡æ¯æµã€‚点击 + åŽ»å°†ä»–ä»¬æ·»åŠ åˆ°ä½ çš„å›ºå®šä¿¡æ¯æµåˆ—表ä¸ã€‚" +msgstr "查看一些推èçš„ä¿¡æ¯æµã€‚点击 + åŽ»å°†ä»–ä»¬æ–°å¢žåˆ°ä½ çš„å›ºå®šä¿¡æ¯æµåˆ—表ä¸ã€‚" #: src/view/com/auth/onboarding/RecommendedFollows.tsx:185 msgid "Check out some recommended users. Follow them to see similar users." @@ -663,9 +663,9 @@ msgstr "é€‰æ‹©å¯æ”¹è¿›ä½ è‡ªå®šä¹‰ä¿¡æ¯æµçš„算法。" #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:103 msgid "Choose your main feeds" -msgstr "é€‰æ‹©ä½ çš„é¦–é€‰ä¿¡æ¯æµ" +msgstr "é€‰æ‹©ä½ çš„ä¸»è¦ä¿¡æ¯æµ" -#: src/view/com/auth/create/Step1.tsx:219 +#: src/view/com/auth/create/Step1.tsx:196 msgid "Choose your password" msgstr "é€‰æ‹©ä½ çš„å¯†ç " @@ -696,11 +696,14 @@ msgstr "清除æœç´¢åކå²è®°å½•" msgid "click here" msgstr "点击这里" -#: src/components/RichText.tsx:189 -#: src/components/TagMenu/index.web.tsx:125 +#: src/components/TagMenu/index.web.tsx:138 msgid "Click here to open tag menu for {tag}" msgstr "" +#: src/components/RichText.tsx:191 +msgid "Click here to open tag menu for #{tag}" +msgstr "" + #: src/screens/Onboarding/index.tsx:35 msgid "Climate" msgstr "气象" @@ -710,8 +713,8 @@ msgstr "气象" msgid "Close" msgstr "å…³é—" -#: src/components/Dialog/index.web.tsx:80 -#: src/components/Dialog/index.web.tsx:194 +#: src/components/Dialog/index.web.tsx:84 +#: src/components/Dialog/index.web.tsx:198 msgid "Close active dialog" msgstr "关闿´»åŠ¨å¯¹è¯æ¡†" @@ -721,7 +724,7 @@ msgstr "å…³é—è¦å‘Š" #: src/view/com/util/BottomSheetCustomBackdrop.tsx:33 msgid "Close bottom drawer" -msgstr "å…³é—åº•æ æŠ½å±‰" +msgstr "å…³é—底部抽屉" #: src/view/com/lightbox/ImageViewing/components/ImageDefaultHeader.tsx:26 msgid "Close image" @@ -735,13 +738,13 @@ msgstr "å…³é—图片查看器" msgid "Close navigation footer" msgstr "å…³é—导航页脚" -#: src/components/TagMenu/index.tsx:266 +#: src/components/TagMenu/index.tsx:262 msgid "Close this dialog" -msgstr "" +msgstr "å…³é—该窗å£" #: src/view/shell/index.web.tsx:52 msgid "Closes bottom navigation bar" -msgstr "å…³é—底æ " +msgstr "å…³é—底部导航æ " #: src/view/com/auth/login/PasswordUpdatedForm.tsx:39 msgid "Closes password update alert" @@ -755,7 +758,7 @@ msgstr "å…³é—帖å编辑页并丢弃è‰ç¨¿" msgid "Closes viewer for header image" msgstr "关闿 ‡é¢˜å›¾ç‰‡æŸ¥çœ‹å™¨" -#: src/view/com/notifications/FeedItem.tsx:317 +#: src/view/com/notifications/FeedItem.tsx:318 msgid "Collapses list of users for a given notification" msgstr "折å 给定通知的用户列表" @@ -767,7 +770,7 @@ msgstr "喜剧" msgid "Comics" msgstr "漫画" -#: src/Navigation.tsx:227 +#: src/Navigation.tsx:229 #: src/view/screens/CommunityGuidelines.tsx:32 msgid "Community Guidelines" msgstr "社群准则" @@ -778,7 +781,7 @@ msgstr "完æˆå¼•å¯¼å¹¶å¼€å§‹ä½¿ç”¨ä½ çš„è´¦æˆ·" #: src/view/com/auth/create/Step3.tsx:73 msgid "Complete the challenge" -msgstr "" +msgstr "完æˆéªŒè¯" #: src/view/com/composer/Composer.tsx:424 msgid "Compose posts up to {MAX_GRAPHEME_LENGTH} characters in length" @@ -792,7 +795,7 @@ msgstr "撰写回å¤" msgid "Configure content filtering setting for category: {0}" msgstr "é…置类别的内容过滤设置:{0}" -#: src/components/Prompt.tsx:113 +#: src/components/Prompt.tsx:124 #: src/view/com/modals/AppealLabel.tsx:98 #: src/view/com/modals/SelfLabel.tsx:154 #: src/view/com/modals/VerifyEmail.tsx:231 @@ -832,8 +835,8 @@ msgid "Confirmation code" msgstr "验è¯ç " #: src/view/com/modals/Waitlist.tsx:120 -msgid "Confirms signing up {email} to the waitlist" -msgstr "确认将 {email} 注册到候补列表" +#~ msgid "Confirms signing up {email} to the waitlist" +#~ msgstr "确认将 {email} 注册到候补列表" #: src/view/com/auth/create/CreateAccount.tsx:193 #: src/view/com/auth/login/LoginForm.tsx:278 @@ -893,7 +896,7 @@ msgstr "ç»§ç»ä¸‹ä¸€æ¥" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:191 msgid "Continue to the next step without following any accounts" -msgstr "ä¸å…³æ³¨ä»»ä½•账户,继ç»ä¸‹ä¸€æ¥" +msgstr "ç»§ç»ä¸‹ä¸€æ¥ï¼Œä¸å…³æ³¨ä»»ä½•账户" #: src/screens/Onboarding/index.tsx:44 msgid "Cooking" @@ -910,13 +913,13 @@ msgstr "å·²å¤åˆ¶æž„建版本å·è‡³å‰ªè´´æ¿" #: src/view/com/modals/AddAppPasswords.tsx:76 #: src/view/com/modals/InviteCodes.tsx:152 -#: src/view/com/util/forms/PostDropdownBtn.tsx:143 +#: src/view/com/util/forms/PostDropdownBtn.tsx:161 msgid "Copied to clipboard" msgstr "å·²å¤åˆ¶è‡³å‰ªè´´æ¿" #: src/view/com/modals/AddAppPasswords.tsx:189 msgid "Copies app password" -msgstr "å·²å¤åˆ¶ App 专用密ç " +msgstr "å·²å¤åˆ¶åº”用专用密ç " #: src/view/com/modals/AddAppPasswords.tsx:188 msgid "Copy" @@ -926,7 +929,8 @@ msgstr "å¤åˆ¶" msgid "Copy link to list" msgstr "å¤åˆ¶åˆ—表链接" -#: src/view/com/util/forms/PostDropdownBtn.tsx:184 +#: src/view/com/util/forms/PostDropdownBtn.tsx:231 +#: src/view/com/util/forms/PostDropdownBtn.tsx:237 msgid "Copy link to post" msgstr "å¤åˆ¶å¸–å链接" @@ -934,11 +938,12 @@ msgstr "å¤åˆ¶å¸–å链接" msgid "Copy link to profile" msgstr "å¤åˆ¶ä¸ªäººèµ„料链接" -#: src/view/com/util/forms/PostDropdownBtn.tsx:170 +#: src/view/com/util/forms/PostDropdownBtn.tsx:223 +#: src/view/com/util/forms/PostDropdownBtn.tsx:225 msgid "Copy post text" msgstr "å¤åˆ¶å¸–åæ–‡å—" -#: src/Navigation.tsx:232 +#: src/Navigation.tsx:234 #: src/view/screens/CopyrightPolicy.tsx:29 msgid "Copyright Policy" msgstr "版æƒè®¸å¯" @@ -947,7 +952,7 @@ msgstr "版æƒè®¸å¯" msgid "Could not load feed" msgstr "æ— æ³•åŠ è½½ä¿¡æ¯æµ" -#: src/view/screens/ProfileList.tsx:888 +#: src/view/screens/ProfileList.tsx:893 msgid "Could not load list" msgstr "æ— æ³•åŠ è½½åˆ—è¡¨" @@ -971,7 +976,7 @@ msgstr "创建账户" #: src/view/com/modals/AddAppPasswords.tsx:226 msgid "Create App Password" -msgstr "创建 App 专用密ç " +msgstr "创建应用专用密ç " #: src/view/com/auth/HomeLoggedOutCTA.tsx:54 #: src/view/com/auth/SplashScreen.tsx:68 @@ -1001,7 +1006,7 @@ msgstr "文化" #: src/view/com/auth/server-input/index.tsx:95 #: src/view/com/auth/server-input/index.tsx:96 msgid "Custom" -msgstr "" +msgstr "自定义" #: src/view/com/modals/ChangeHandle.tsx:389 msgid "Custom domain" @@ -1010,7 +1015,7 @@ msgstr "自定义域å" #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:106 #: src/view/screens/Feeds.tsx:692 msgid "Custom feeds built by the community bring you new experiences and help you find the content you love." -msgstr "ç”±ç¤¾åŒºæž„å»ºçš„è‡ªå®šä¹‰ä¿¡æ¯æµèƒ½ä¸ºä½ å¸¦æ¥æ–°çš„ä½“éªŒï¼Œå¹¶å¸®åŠ©ä½ æ‰¾åˆ°ä½ å–œæ¬¢çš„å†…å®¹ã€‚" +msgstr "ç”±ç¤¾ç¾¤æž„å»ºçš„è‡ªå®šä¹‰ä¿¡æ¯æµèƒ½ä¸ºä½ å¸¦æ¥æ–°çš„ä½“éªŒï¼Œå¹¶å¸®åŠ©ä½ æ‰¾åˆ°ä½ å–œæ¬¢çš„å†…å®¹ã€‚" #: src/view/screens/PreferencesExternalEmbeds.tsx:55 msgid "Customize media from external sites." @@ -1048,7 +1053,7 @@ msgstr "åˆ é™¤è´¦å·" #: src/view/screens/AppPasswords.tsx:222 #: src/view/screens/AppPasswords.tsx:242 msgid "Delete app password" -msgstr "åˆ é™¤ App 专用密ç " +msgstr "åˆ é™¤åº”ç”¨ä¸“ç”¨å¯†ç " #: src/view/screens/ProfileList.tsx:364 #: src/view/screens/ProfileList.tsx:445 @@ -1067,11 +1072,12 @@ msgstr "åˆ é™¤æˆ‘çš„è´¦æˆ·" msgid "Delete My Account…" msgstr "åˆ é™¤æˆ‘çš„è´¦æˆ·â€¦" -#: src/view/com/util/forms/PostDropdownBtn.tsx:273 +#: src/view/com/util/forms/PostDropdownBtn.tsx:317 +#: src/view/com/util/forms/PostDropdownBtn.tsx:326 msgid "Delete post" msgstr "åˆ é™¤å¸–å" -#: src/view/com/util/forms/PostDropdownBtn.tsx:277 +#: src/view/com/util/forms/PostDropdownBtn.tsx:321 msgid "Delete this post?" msgstr "åˆ é™¤è¿™æ¡å¸–å?" @@ -1125,7 +1131,7 @@ msgstr "æŽ¢ç´¢æ–°çš„è‡ªå®šä¹‰ä¿¡æ¯æµ" #: src/view/screens/Feeds.tsx:689 msgid "Discover New Feeds" -msgstr "" +msgstr "æŽ¢ç´¢æ–°çš„ä¿¡æ¯æµ" #: src/view/com/modals/EditProfile.tsx:192 msgid "Display name" @@ -1140,8 +1146,8 @@ msgid "Domain verified!" msgstr "域å已认è¯ï¼" #: src/view/com/auth/create/Step1.tsx:170 -msgid "Don't have an invite code?" -msgstr "没有邀请ç ?" +#~ msgid "Don't have an invite code?" +#~ msgstr "没有邀请ç ?" #: src/view/com/auth/onboarding/RecommendedFollows.tsx:86 #: src/view/com/modals/EditImage.tsx:333 @@ -1182,44 +1188,44 @@ msgstr "åŒå‡»ä»¥ç™»å½•" #: src/view/screens/Settings/index.tsx:755 msgid "Download Bluesky account data (repository)" -msgstr "" +msgstr "ä¸‹è½½ä½ çš„ Bluesky 账户数æ®ï¼ˆæ•°æ®åº“)" #: src/view/screens/Settings/ExportCarDialog.tsx:59 #: src/view/screens/Settings/ExportCarDialog.tsx:63 msgid "Download CAR file" -msgstr "" +msgstr "下载 CAR 文件" #: src/view/com/composer/text-input/TextInput.web.tsx:249 msgid "Drop to add images" -msgstr "拖放å³å¯æ·»åŠ å›¾ç‰‡" +msgstr "拖放å³å¯æ–°å¢žå›¾ç‰‡" #: src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx:111 msgid "Due to Apple policies, adult content can only be enabled on the web after completing sign up." -msgstr "å— Apple 政ç–é™åˆ¶ï¼Œæˆäººå†…容åªèƒ½åœ¨å®Œæˆæ³¨å†ŒåŽåœ¨ç½‘页端å¯ç”¨æ˜¾ç¤ºã€‚" +msgstr "å— Apple 政ç–é™åˆ¶ï¼Œæ˜¾ç¤ºæˆäººå†…容åªèƒ½åœ¨å®Œæˆæ³¨å†ŒåŽåœ¨ç½‘页端设置ä¸å¯ç”¨ã€‚" #: src/view/com/modals/EditProfile.tsx:185 msgid "e.g. Alice Roberts" -msgstr "ä¾‹ï¼šå¼ è“天" +msgstr "ä¾‹å¦‚ï¼šå¼ è“天" #: src/view/com/modals/EditProfile.tsx:203 msgid "e.g. Artist, dog-lover, and avid reader." -msgstr "例:普通艺术家一枚,喜欢撸猫。" +msgstr "例如:艺术家ã€çˆ±ç‹—人士和狂çƒè¯»è€…。" #: src/view/com/modals/CreateOrEditList.tsx:283 msgid "e.g. Great Posters" -msgstr "例:å‘布é‡è¦å¸–å的用户" +msgstr "例如:优秀的å‘帖者" #: src/view/com/modals/CreateOrEditList.tsx:284 msgid "e.g. Spammers" -msgstr "ä¾‹ï¼šåžƒåœ¾å†…å®¹åˆ¶é€ è€…" +msgstr "ä¾‹å¦‚ï¼šåžƒåœ¾å†…å®¹åˆ¶é€ è€…" #: src/view/com/modals/CreateOrEditList.tsx:312 msgid "e.g. The posters who never miss." -msgstr "ä¾‹ï¼šä½ ç»ä¸èƒ½é”™è¿‡å…¶å‘布帖å的用户。" +msgstr "例如:ç»ä¸å®¹é”™è¿‡çš„å‘帖者。" #: src/view/com/modals/CreateOrEditList.tsx:313 msgid "e.g. Users that repeatedly reply with ads." -msgstr "例:散布广告内容的用户。" +msgstr "例如:散布广告内容的用户。" #: src/view/com/modals/InviteCodes.tsx:96 msgid "Each code works once. You'll receive more invite codes periodically." @@ -1243,7 +1249,7 @@ msgstr "编辑列表详情" msgid "Edit Moderation List" msgstr "编辑é™åˆ¶åˆ—表" -#: src/Navigation.tsx:242 +#: src/Navigation.tsx:244 #: src/view/screens/Feeds.tsx:434 #: src/view/screens/SavedFeeds.tsx:84 msgid "Edit My Feeds" @@ -1255,13 +1261,13 @@ msgstr "编辑个人资料" #: src/view/com/profile/ProfileHeader.tsx:418 msgid "Edit profile" -msgstr "编辑资料" +msgstr "编辑个人资料" #: src/view/com/profile/ProfileHeader.tsx:423 msgid "Edit Profile" -msgstr "编辑资料" +msgstr "编辑个人资料" -#: src/view/com/home/HomeHeaderLayout.web.tsx:59 +#: src/view/com/home/HomeHeaderLayout.web.tsx:62 #: src/view/screens/Feeds.tsx:355 msgid "Edit Saved Feeds" msgstr "编辑ä¿å˜çš„ä¿¡æ¯æµ" @@ -1282,14 +1288,13 @@ msgstr "ç¼–è¾‘ä½ çš„è´¦æˆ·æè¿°" msgid "Education" msgstr "教育" -#: src/view/com/auth/create/Step1.tsx:199 +#: src/view/com/auth/create/Step1.tsx:176 #: src/view/com/auth/login/ForgotPasswordForm.tsx:156 #: src/view/com/modals/ChangeEmail.tsx:141 -#: src/view/com/modals/Waitlist.tsx:88 msgid "Email" msgstr "电å邮箱" -#: src/view/com/auth/create/Step1.tsx:190 +#: src/view/com/auth/create/Step1.tsx:167 #: src/view/com/auth/login/ForgotPasswordForm.tsx:147 msgid "Email address" msgstr "邮箱地å€" @@ -1338,16 +1343,16 @@ msgstr "å¯ç”¨æ¤è®¾ç½®ä»¥ä»…æŸ¥çœ‹ä½ å…³æ³¨çš„äººä¹‹é—´çš„å›žå¤ã€‚" #: src/view/screens/Profile.tsx:455 msgid "End of feed" -msgstr "结æŸä¿¡æ¯æµ" +msgstr "ä¿¡æ¯æµçš„æœ«å°¾" #: src/view/com/modals/AddAppPasswords.tsx:166 msgid "Enter a name for this App Password" -msgstr "ä¸ºæ¤ App 专用密ç 命å" +msgstr "为æ¤åº”用专用密ç 命å" -#: src/components/dialogs/MutedWords.tsx:87 -#: src/components/dialogs/MutedWords.tsx:88 +#: src/components/dialogs/MutedWords.tsx:100 +#: src/components/dialogs/MutedWords.tsx:101 msgid "Enter a word or tag" -msgstr "" +msgstr "è¾“å…¥ä¸€ä¸ªè¯æˆ–æ ‡ç¾" #: src/view/com/modals/VerifyEmail.tsx:105 msgid "Enter Confirmation Code" @@ -1363,18 +1368,18 @@ msgstr "è¾“å…¥ä½ æƒ³ä½¿ç”¨çš„åŸŸå" #: src/view/com/auth/login/ForgotPasswordForm.tsx:107 msgid "Enter the email you used to create your account. We'll send you a \"reset code\" so you can set a new password." -msgstr "è¾“å…¥ä½ ç”¨äºŽåˆ›å»ºè´¦æˆ·çš„ç”µå邮箱。我们将å‘ä½ å‘é€é‡ç½®ç ï¼Œä»¥ä¾¿ä½ é‡æ–°è®¾ç½®å¯†ç 。" +msgstr "è¾“å…¥ä½ ç”¨äºŽåˆ›å»ºè´¦æˆ·çš„ç”µå邮箱。我们将å‘ä½ å‘é€ç”¨äºŽå¯†ç é‡è®¾çš„确认ç 。" -#: src/view/com/auth/create/Step1.tsx:251 +#: src/view/com/auth/create/Step1.tsx:228 #: src/view/com/modals/BirthDateSettings.tsx:74 msgid "Enter your birth date" msgstr "è¾“å…¥ä½ çš„å‡ºç”Ÿæ—¥æœŸ" #: src/view/com/modals/Waitlist.tsx:78 -msgid "Enter your email" -msgstr "è¾“å…¥ä½ çš„ç”µå邮箱" +#~ msgid "Enter your email" +#~ msgstr "è¾“å…¥ä½ çš„ç”µå邮箱" -#: src/view/com/auth/create/Step1.tsx:195 +#: src/view/com/auth/create/Step1.tsx:172 msgid "Enter your email address" msgstr "è¾“å…¥ä½ çš„ç”µå邮箱" @@ -1396,7 +1401,7 @@ msgstr "è¾“å…¥ä½ çš„ç”¨æˆ·å和密ç " #: src/view/com/auth/create/Step3.tsx:67 msgid "Error receiving captcha response." -msgstr "" +msgstr "Captcha å“应错误" #: src/view/screens/Search/Search.tsx:110 msgid "Error:" @@ -1417,11 +1422,11 @@ msgstr "退出图片查看器" #: src/view/com/modals/ListAddRemoveUsers.tsx:88 #: src/view/shell/desktop/Search.tsx:235 msgid "Exits inputting search query" -msgstr "退出æœç´¢æŸ¥è¯¢" +msgstr "退出æœç´¢æŸ¥è¯¢è¾“å…¥" #: src/view/com/modals/Waitlist.tsx:138 -msgid "Exits signing up for waitlist with {email}" -msgstr "å°† {email} 从候补列表ä¸ç§»é™¤" +#~ msgid "Exits signing up for waitlist with {email}" +#~ msgstr "å°† {email} 从候补列表ä¸ç§»é™¤" #: src/view/com/lightbox/Lightbox.web.tsx:163 msgid "Expand alt text" @@ -1434,12 +1439,12 @@ msgstr "展开或折å ä½ è¦å›žå¤çš„完整帖å" #: src/view/screens/Settings/index.tsx:753 msgid "Export my data" -msgstr "" +msgstr "å¯¼å‡ºè´¦å·æ•°æ®" #: src/view/screens/Settings/ExportCarDialog.tsx:44 #: src/view/screens/Settings/index.tsx:764 msgid "Export My Data" -msgstr "" +msgstr "å¯¼å‡ºè´¦å·æ•°æ®" #: src/view/com/modals/EmbedConsent.tsx:64 msgid "External Media" @@ -1450,7 +1455,7 @@ msgstr "外部媒体" msgid "External media may allow websites to collect information about you and your device. No information is sent or requested until you press the \"play\" button." msgstr "外部媒体å¯èƒ½å…è®¸ç½‘ç«™æ”¶é›†æœ‰å…³ä½ å’Œä½ è®¾å¤‡çš„æœ‰å…³ä¿¡æ¯ã€‚åœ¨ä½ æŒ‰ä¸‹\"查看\"按钮之å‰ï¼Œå°†ä¸ä¼šå‘逿ˆ–请求任何外部信æ¯ã€‚" -#: src/Navigation.tsx:261 +#: src/Navigation.tsx:263 #: src/view/screens/PreferencesExternalEmbeds.tsx:52 #: src/view/screens/Settings/index.tsx:657 msgid "External Media Preferences" @@ -1463,13 +1468,13 @@ msgstr "外部媒体设置" #: src/view/com/modals/AddAppPasswords.tsx:115 #: src/view/com/modals/AddAppPasswords.tsx:119 msgid "Failed to create app password." -msgstr "创建 App 专用密ç 失败。" +msgstr "创建应用专用密ç 失败。" #: src/view/com/modals/CreateOrEditList.tsx:206 msgid "Failed to create the list. Check your internet connection and try again." msgstr "æ— æ³•åˆ›å»ºåˆ—è¡¨ã€‚è¯·æ£€æŸ¥ä½ çš„äº’è”网连接并é‡è¯•。" -#: src/view/com/util/forms/PostDropdownBtn.tsx:110 +#: src/view/com/util/forms/PostDropdownBtn.tsx:128 msgid "Failed to delete post, please try again" msgstr "æ— æ³•åˆ é™¤å¸–å,请é‡è¯•" @@ -1478,13 +1483,13 @@ msgstr "æ— æ³•åˆ é™¤å¸–å,请é‡è¯•" msgid "Failed to load recommended feeds" msgstr "æ— æ³•åŠ è½½æŽ¨èä¿¡æ¯æµ" -#: src/Navigation.tsx:192 +#: src/Navigation.tsx:194 msgid "Feed" msgstr "ä¿¡æ¯æµ" #: src/view/com/feeds/FeedSourceCard.tsx:231 msgid "Feed by {0}" -msgstr "ä¿¡æ¯æµç”± {0} 创建" +msgstr "ç”± {0} åˆ›å»ºçš„ä¿¡æ¯æµ" #: src/view/screens/Feeds.tsx:605 msgid "Feed offline" @@ -1499,7 +1504,7 @@ msgstr "ä¿¡æ¯æµå·²ç¦»çº¿" msgid "Feedback" msgstr "å馈" -#: src/Navigation.tsx:445 +#: src/Navigation.tsx:452 #: src/view/screens/Feeds.tsx:419 #: src/view/screens/Feeds.tsx:524 #: src/view/screens/Profile.tsx:184 @@ -1524,7 +1529,7 @@ msgstr "åˆ›å»ºä¿¡æ¯æµè¦æ±‚一些编程基础。查看 <0/> 以获å–详情。 #: src/screens/Onboarding/StepTopicalFeeds.tsx:76 msgid "Feeds can be topical as well!" -msgstr "ä¿¡æ¯æµä¹Ÿå¯ä»¥æ˜¯è¯é¢˜æ€§çš„ï¼" +msgstr "ä¿¡æ¯æµä¹Ÿå¯ä»¥å›´ç»•æŸäº›è¯é¢˜ï¼" #: src/screens/Onboarding/StepFinished.tsx:151 msgid "Finalizing" @@ -1542,23 +1547,23 @@ msgstr "寻找一些æ£åœ¨ä½¿ç”¨ Bluesky 的用户" #: src/view/screens/Search/Search.tsx:438 msgid "Find users with the search tool on the right" -msgstr "使用å³ä¾§çš„å·¥å…·æ¥æœç´¢ç”¨æˆ·" +msgstr "使用å³ä¾§çš„æœç´¢å·¥å…·æ¥æŸ¥æ‰¾ç”¨æˆ·" #: src/view/com/auth/onboarding/RecommendedFollowsItem.tsx:150 msgid "Finding similar accounts..." -msgstr "寻找类似的账户..." +msgstr "æ£åœ¨å¯»æ‰¾ç±»ä¼¼çš„账户..." #: src/view/screens/PreferencesFollowingFeed.tsx:111 msgid "Fine-tune the content you see on your Following feed." -msgstr "" +msgstr "è°ƒæ•´ä½ åœ¨å…³æ³¨ä¿¡æ¯æµä¸Šæ‰€çœ‹åˆ°çš„内容。" #: src/view/screens/PreferencesHomeFeed.tsx:111 #~ msgid "Fine-tune the content you see on your home screen." -#~ msgstr "å¾®è°ƒä½ åœ¨ä¸»é¡µä¸Šæ‰€çœ‹åˆ°çš„å†…å®¹ã€‚" +#~ msgstr "è°ƒæ•´ä½ åœ¨ä¸»é¡µä¸Šæ‰€çœ‹åˆ°çš„å†…å®¹ã€‚" #: src/view/screens/PreferencesThreads.tsx:60 msgid "Fine-tune the discussion threads." -msgstr "微调讨论主题。" +msgstr "调整讨论主题。" #: src/screens/Onboarding/index.tsx:38 msgid "Fitness" @@ -1620,7 +1625,7 @@ msgstr "ä»…é™å·²å…³æ³¨çš„用户" #: src/view/com/notifications/FeedItem.tsx:166 msgid "followed you" -msgstr "已关注" +msgstr "å…³æ³¨äº†ä½ " #: src/view/screens/ProfileFollowers.tsx:25 msgid "Followers" @@ -1636,21 +1641,21 @@ msgstr "æ£åœ¨å…³æ³¨" msgid "Following {0}" msgstr "æ£åœ¨å…³æ³¨ {0}" -#: src/Navigation.tsx:248 -#: src/view/com/home/HomeHeaderLayout.web.tsx:45 -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:83 +#: src/Navigation.tsx:250 +#: src/view/com/home/HomeHeaderLayout.web.tsx:50 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:84 #: src/view/screens/PreferencesFollowingFeed.tsx:104 #: src/view/screens/Settings/index.tsx:543 msgid "Following Feed Preferences" -msgstr "" +msgstr "å…³æ³¨ä¿¡æ¯æµé¦–选项" #: src/view/com/profile/ProfileHeader.tsx:546 msgid "Follows you" -msgstr "已关注" +msgstr "å…³æ³¨äº†ä½ " #: src/view/com/profile/ProfileCard.tsx:141 msgid "Follows You" -msgstr "已关注" +msgstr "å…³æ³¨äº†ä½ " #: src/screens/Onboarding/index.tsx:43 msgid "Food" @@ -1677,6 +1682,11 @@ msgstr "忘记密ç " msgid "Forgot Password" msgstr "忘记密ç " +#: src/screens/Hashtag.tsx:108 +#: src/screens/Hashtag.tsx:148 +msgid "From @{sanitizedAuthor}" +msgstr "æ¥è‡ª @{sanitizedAuthor}" + #: src/view/com/posts/FeedItem.tsx:189 msgctxt "from-feed" msgid "From <0/>" @@ -1700,8 +1710,8 @@ msgstr "返回" #: src/view/screens/ProfileFeed.tsx:106 #: src/view/screens/ProfileFeed.tsx:111 -#: src/view/screens/ProfileList.tsx:897 #: src/view/screens/ProfileList.tsx:902 +#: src/view/screens/ProfileList.tsx:907 msgid "Go Back" msgstr "返回" @@ -1713,7 +1723,7 @@ msgstr "返回上一æ¥" #: src/view/screens/Search/Search.tsx:747 #: src/view/shell/desktop/Search.tsx:262 msgid "Go to @{queryMaybeHandle}" -msgstr "转到 @{queryMaybeHandle}" +msgstr "å‰å¾€ @{queryMaybeHandle}" #: src/view/com/auth/login/ForgotPasswordForm.tsx:189 #: src/view/com/auth/login/ForgotPasswordForm.tsx:218 @@ -1721,15 +1731,23 @@ msgstr "转到 @{queryMaybeHandle}" #: src/view/com/auth/login/SetNewPasswordForm.tsx:195 #: src/view/com/modals/ChangePassword.tsx:165 msgid "Go to next" -msgstr "转到下一个" +msgstr "å‰å¾€ä¸‹ä¸€æ¥" #: src/view/com/modals/ChangeHandle.tsx:265 msgid "Handle" msgstr "用户识别符" +#: src/Navigation.tsx:270 +msgid "Hashtag" +msgstr "è¯é¢˜æ ‡ç¾" + #: src/components/RichText.tsx:188 -msgid "Hashtag: {tag}" -msgstr "" +#~ msgid "Hashtag: {tag}" +#~ msgstr "è¯é¢˜æ ‡ç¾ï¼š{tag}" + +#: src/components/RichText.tsx:190 +msgid "Hashtag: #{tag}" +msgstr "è¯é¢˜æ ‡ç¾ï¼š#{tag}" #: src/view/com/auth/create/CreateAccount.tsx:208 msgid "Having trouble?" @@ -1742,19 +1760,19 @@ msgstr "帮助" #: src/screens/Onboarding/StepSuggestedAccounts/index.tsx:132 msgid "Here are some accounts for you to follow" -msgstr "这里是一些推è关注的用户" +msgstr "这里有一些推è关注的用户" #: src/screens/Onboarding/StepTopicalFeeds.tsx:85 msgid "Here are some popular topical feeds. You can choose to follow as many as you like." -msgstr "这里是一些æµè¡Œçš„ä¿¡æ¯æµä¾›ä½ 挑选。" +msgstr "这里有一些æµè¡Œçš„ä¿¡æ¯æµä¾›ä½ 挑选。" #: src/screens/Onboarding/StepTopicalFeeds.tsx:80 msgid "Here are some topical feeds based on your interests: {interestsText}. You can choose to follow as many as you like." -msgstr "è¿™é‡Œæ˜¯ä¸€äº›åŸºäºŽä½ å…´è¶£æ‰€æŽ¨èçš„ä¿¡æ¯æµä¾›ä½ 挑选:{interestsText}。" +msgstr "è¿™é‡Œæœ‰ä¸€äº›åŸºäºŽä½ å…´è¶£æ‰€æŽ¨èçš„ä¿¡æ¯æµä¾›ä½ 挑选:{interestsText}ã€‚å…³æ³¨çš„ä¿¡æ¯æµæ•°é‡æ²¡æœ‰é™åˆ¶ã€‚" #: src/view/com/modals/AddAppPasswords.tsx:153 msgid "Here is your app password." -msgstr "è¿™é‡Œæ˜¯ä½ çš„ App 专用密ç 。" +msgstr "è¿™é‡Œæ˜¯ä½ çš„åº”ç”¨ä¸“ç”¨å¯†ç 。" #: src/screens/Onboarding/StepModeration/ModerationOption.tsx:41 #: src/view/com/modals/ContentFilteringSettings.tsx:251 @@ -1764,12 +1782,13 @@ msgid "Hide" msgstr "éšè—" #: src/view/com/modals/ContentFilteringSettings.tsx:224 -#: src/view/com/notifications/FeedItem.tsx:325 +#: src/view/com/notifications/FeedItem.tsx:326 msgctxt "action" msgid "Hide" msgstr "éšè—" -#: src/view/com/util/forms/PostDropdownBtn.tsx:232 +#: src/view/com/util/forms/PostDropdownBtn.tsx:276 +#: src/view/com/util/forms/PostDropdownBtn.tsx:287 msgid "Hide post" msgstr "éšè—帖å" @@ -1778,11 +1797,11 @@ msgstr "éšè—帖å" msgid "Hide the content" msgstr "éšè—内容" -#: src/view/com/util/forms/PostDropdownBtn.tsx:236 +#: src/view/com/util/forms/PostDropdownBtn.tsx:280 msgid "Hide this post?" msgstr "éšè—è¿™æ¡å¸–å?" -#: src/view/com/notifications/FeedItem.tsx:315 +#: src/view/com/notifications/FeedItem.tsx:316 msgid "Hide user list" msgstr "éšè—用户列表" @@ -1810,7 +1829,7 @@ msgstr "ä¿¡æ¯æµæœåŠ¡å™¨è¿”å›žé”™è¯¯çš„å“应,请è”ç³»ä¿¡æ¯æµçš„维护者 msgid "Hmm, we're having trouble finding this feed. It may have been deleted." msgstr "æˆ‘ä»¬æ— æ³•æ‰¾åˆ°è¯¥ä¿¡æ¯æµï¼Œä¼¼ä¹Žå·²è¢«åˆ 除。" -#: src/Navigation.tsx:435 +#: src/Navigation.tsx:442 #: src/view/shell/bottom-bar/BottomBar.tsx:137 #: src/view/shell/desktop/LeftNav.tsx:306 #: src/view/shell/Drawer.tsx:398 @@ -1825,7 +1844,7 @@ msgstr "主页" #~ msgid "Home Feed Preferences" #~ msgstr "ä¸»é¡µä¿¡æ¯æµé¦–选项" -#: src/view/com/auth/create/Step1.tsx:82 +#: src/view/com/auth/create/Step1.tsx:75 #: src/view/com/auth/login/ForgotPasswordForm.tsx:120 msgid "Hosting provider" msgstr "托管æœåŠ¡æä¾›å•†" @@ -1856,7 +1875,7 @@ msgstr "è‹¥ä¸å‹¾é€‰ï¼Œåˆ™é»˜è®¤ä¸ºå…¨å¹´é¾„å‘。" #: src/view/com/modals/ChangePassword.tsx:146 msgid "If you want to change your password, we will send you a code to verify that this is your account." -msgstr "å¦‚æžœä½ æƒ³è¦æ›´æ”¹å¯†ç ,我们将å‘ä½ å‘é€ä¸€ä¸ªç¡®è®¤ç 以验è¯è¿™æ˜¯ä½ 的账户。" +msgstr "å¦‚æžœä½ æƒ³è¦æ›´æ”¹å¯†ç ,我们将å‘ä½ å‘é€ä¸€ä¸ªéªŒè¯ç 以验è¯è¿™æ˜¯ä½ 的账户。" #: src/view/com/util/images/Gallery.tsx:38 msgid "Image" @@ -1879,17 +1898,17 @@ msgstr "输入å‘é€åˆ°ä½ 电å邮箱的验è¯ç 以é‡ç½®å¯†ç " msgid "Input confirmation code for account deletion" msgstr "è¾“å…¥åˆ é™¤ç”¨æˆ·çš„éªŒè¯ç " -#: src/view/com/auth/create/Step1.tsx:200 +#: src/view/com/auth/create/Step1.tsx:177 msgid "Input email for Bluesky account" msgstr "输入 Bluesky 账户的电å邮箱" -#: src/view/com/auth/create/Step1.tsx:158 +#: src/view/com/auth/create/Step1.tsx:151 msgid "Input invite code to proceed" msgstr "输入邀请ç 以继ç»" #: src/view/com/modals/AddAppPasswords.tsx:180 msgid "Input name for app password" -msgstr "输入 App 专用密ç åç§°" +msgstr "输入应用专用密ç åç§°" #: src/view/com/auth/login/SetNewPasswordForm.tsx:162 msgid "Input new password" @@ -1913,11 +1932,11 @@ msgstr "è¾“å…¥æ³¨å†Œæ—¶ä½¿ç”¨çš„ç”¨æˆ·åæˆ–电å邮箱" #: src/view/com/auth/create/Step2.tsx:271 #~ msgid "Input the verification code we have texted to you" -#~ msgstr "输入收到的çŸä¿¡éªŒè¯ç " +#~ msgstr "输入我们å‘é€åˆ°ä½ 手机的çŸä¿¡éªŒè¯ç " #: src/view/com/modals/Waitlist.tsx:90 -msgid "Input your email to get on the Bluesky waitlist" -msgstr "è¾“å…¥ä½ çš„ç”µåé‚®ç®±ä»¥åŠ å…¥ Bluesky 候补列表" +#~ msgid "Input your email to get on the Bluesky waitlist" +#~ msgstr "è¾“å…¥ä½ çš„ç”µåé‚®ç®±ä»¥åŠ å…¥ Bluesky 候补列表" #: src/view/com/auth/login/LoginForm.tsx:229 msgid "Input your password" @@ -1943,8 +1962,8 @@ msgstr "ç”¨æˆ·åæˆ–å¯†ç æ— 效" msgid "Invite a Friend" msgstr "邀请朋å‹" -#: src/view/com/auth/create/Step1.tsx:148 -#: src/view/com/auth/create/Step1.tsx:157 +#: src/view/com/auth/create/Step1.tsx:141 +#: src/view/com/auth/create/Step1.tsx:150 msgid "Invite code" msgstr "邀请ç " @@ -1954,7 +1973,7 @@ msgstr "é‚€è¯·ç æ— æ•ˆï¼Œè¯·æ£€æŸ¥ä½ è¾“å…¥çš„é‚€è¯·ç å¹¶é‡è¯•。" #: src/view/com/modals/InviteCodes.tsx:170 msgid "Invite codes: {0} available" -msgstr "邀请ç :{0} å¯ç”¨" +msgstr "邀请ç :{0} 个å¯ç”¨" #: src/view/shell/Drawer.tsx:645 #~ msgid "Invite codes: {invitesAvailable} available" @@ -1962,7 +1981,7 @@ msgstr "邀请ç :{0} å¯ç”¨" #: src/view/com/modals/InviteCodes.tsx:169 msgid "Invite codes: 1 available" -msgstr "邀请ç :1 å¯ç”¨" +msgstr "邀请ç :1 个å¯ç”¨" #: src/screens/Onboarding/StepFollowingFeed.tsx:64 msgid "It shows posts from the people you follow as they happen." @@ -1974,17 +1993,17 @@ msgid "Jobs" msgstr "工作" #: src/view/com/modals/Waitlist.tsx:67 -msgid "Join the waitlist" -msgstr "åŠ å…¥å€™è¡¥åˆ—è¡¨" +#~ msgid "Join the waitlist" +#~ msgstr "åŠ å…¥å€™è¡¥åˆ—è¡¨" #: src/view/com/auth/create/Step1.tsx:174 #: src/view/com/auth/create/Step1.tsx:178 -msgid "Join the waitlist." -msgstr "åŠ å…¥å€™è¡¥åˆ—è¡¨ã€‚" +#~ msgid "Join the waitlist." +#~ msgstr "åŠ å…¥å€™è¡¥åˆ—è¡¨ã€‚" #: src/view/com/modals/Waitlist.tsx:128 -msgid "Join Waitlist" -msgstr "åŠ å…¥å€™è¡¥åˆ—è¡¨" +#~ msgid "Join Waitlist" +#~ msgstr "åŠ å…¥å€™è¡¥åˆ—è¡¨" #: src/screens/Onboarding/index.tsx:24 msgid "Journalism" @@ -1998,7 +2017,7 @@ msgstr "选择è¯è¨€" msgid "Language settings" msgstr "è¯è¨€è®¾ç½®" -#: src/Navigation.tsx:140 +#: src/Navigation.tsx:142 #: src/view/screens/LanguageSettings.tsx:89 msgid "Language Settings" msgstr "è¯è¨€è®¾ç½®" @@ -2035,7 +2054,7 @@ msgstr "了解有关 Bluesky 公开内容的更多详情。" #: src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx:82 msgid "Leave them all unchecked to see any language." -msgstr "全部ä¸é€‰ä¸ä»¥æŸ¥çœ‹ä»»ä½•è¯è¨€ã€‚" +msgstr "全部留空以查看所有è¯è¨€çš„帖å。" #: src/view/com/modals/LinkWarning.tsx:51 msgid "Leaving Bluesky" @@ -2068,48 +2087,47 @@ msgid "Light" msgstr "亮色" #: src/view/com/util/post-ctrls/PostCtrls.tsx:182 -#: src/view/com/util/post-ctrls/PostCtrls.tsx:216 msgid "Like" -msgstr "点赞" +msgstr "喜欢" #: src/view/screens/ProfileFeed.tsx:591 msgid "Like this feed" -msgstr "ç‚¹èµžè¿™ä¸ªä¿¡æ¯æµ" +msgstr "å–œæ¬¢è¿™ä¸ªä¿¡æ¯æµ" -#: src/Navigation.tsx:197 +#: src/Navigation.tsx:199 msgid "Liked by" -msgstr "点赞" +msgstr "喜欢" #: src/view/screens/PostLikedBy.tsx:27 #: src/view/screens/ProfileFeedLikedBy.tsx:27 msgid "Liked By" -msgstr "点赞" +msgstr "喜欢" #: src/view/com/feeds/FeedSourceCard.tsx:279 msgid "Liked by {0} {1}" -msgstr "{0} {1} 点赞" +msgstr "{0} 个 {1} 喜欢" #: src/view/screens/ProfileFeed.tsx:606 msgid "Liked by {likeCount} {0}" -msgstr "{likeCount} {0} 点赞" +msgstr "{likeCount} 个 {0} 喜欢" #: src/view/com/notifications/FeedItem.tsx:170 msgid "liked your custom feed" -msgstr "ç‚¹èµžä½ çš„è‡ªå®šä¹‰ä¿¡æ¯æµ" +msgstr "èµžäº†ä½ çš„è‡ªå®šä¹‰ä¿¡æ¯æµ" #: src/view/com/notifications/FeedItem.tsx:155 msgid "liked your post" -msgstr "ç‚¹èµžä½ çš„å¸–å" +msgstr "èµžäº†ä½ çš„å¸–å" #: src/view/screens/Profile.tsx:183 msgid "Likes" -msgstr "点赞" +msgstr "喜欢" #: src/view/com/post-thread/PostThreadItem.tsx:183 msgid "Likes on this post" -msgstr "点赞这æ¡å¸–å" +msgstr "è¿™æ¡å¸–å的喜欢数" -#: src/Navigation.tsx:166 +#: src/Navigation.tsx:168 msgid "List" msgstr "列表" @@ -2139,13 +2157,13 @@ msgstr "列表åç§°" #: src/view/screens/ProfileList.tsx:343 msgid "List unblocked" -msgstr "å–æ¶ˆå±è”½åˆ—表" +msgstr "解除对列表的å±è”½" #: src/view/screens/ProfileList.tsx:302 msgid "List unmuted" -msgstr "å–æ¶ˆéšè—列表" +msgstr "解除对列表的éšè—" -#: src/Navigation.tsx:110 +#: src/Navigation.tsx:112 #: src/view/screens/Profile.tsx:185 #: src/view/shell/desktop/LeftNav.tsx:379 #: src/view/shell/Drawer.tsx:492 @@ -2177,7 +2195,7 @@ msgstr "åŠ è½½ä¸..." #~ msgid "Local dev server" #~ msgstr "æœ¬åœ°å¼€å‘æœåС噍" -#: src/Navigation.tsx:207 +#: src/Navigation.tsx:209 msgid "Log" msgstr "日志" @@ -2198,19 +2216,19 @@ msgstr "登录未列出的账户" #: src/view/com/modals/LinkWarning.tsx:65 msgid "Make sure this is where you intend to go!" -msgstr "请确认ï¼" +msgstr "è¯·ç¡®è®¤ç›®æ ‡é¡µé¢åœ°å€æ˜¯å¦æ£ç¡®ï¼" -#: src/components/dialogs/MutedWords.tsx:71 +#: src/components/dialogs/MutedWords.tsx:83 msgid "Manage your muted words and tags" -msgstr "" +msgstr "管ç†ä½ çš„éšè—è¯å’Œè¯é¢˜æ ‡ç¾" #: src/view/com/auth/create/Step2.tsx:118 msgid "May not be longer than 253 characters" -msgstr "" +msgstr "ä¸èƒ½é•¿äºŽ 253 个å—符" #: src/view/com/auth/create/Step2.tsx:109 msgid "May only contain letters and numbers" -msgstr "" +msgstr "åªèƒ½åŒ…å«å—æ¯å’Œæ•°å—" #: src/view/screens/Profile.tsx:182 msgid "Media" @@ -2224,7 +2242,7 @@ msgstr "æåˆ°çš„用户" msgid "Mentioned users" msgstr "æåˆ°çš„用户" -#: src/view/com/util/ViewHeader.tsx:81 +#: src/view/com/util/ViewHeader.tsx:87 #: src/view/screens/Search/Search.tsx:646 msgid "Menu" msgstr "èœå•" @@ -2233,7 +2251,7 @@ msgstr "èœå•" msgid "Message from server: {0}" msgstr "æ¥è‡ªæœåŠ¡å™¨çš„ä¿¡æ¯ï¼š{0}" -#: src/Navigation.tsx:115 +#: src/Navigation.tsx:117 #: src/view/screens/Moderation.tsx:66 #: src/view/screens/Settings/index.tsx:625 #: src/view/shell/desktop/LeftNav.tsx:397 @@ -2245,17 +2263,17 @@ msgstr "é™åˆ¶" #: src/view/com/lists/ListCard.tsx:93 #: src/view/com/modals/UserAddRemoveLists.tsx:206 msgid "Moderation list by {0}" -msgstr "é™åˆ¶åˆ—表由 {0} 创建" +msgstr "ç”± {0} 创建的é™åˆ¶åˆ—表" -#: src/view/screens/ProfileList.tsx:774 +#: src/view/screens/ProfileList.tsx:775 msgid "Moderation list by <0/>" -msgstr "é™åˆ¶åˆ—表由 </0> 创建" +msgstr "ç”± </0> 创建的é™åˆ¶åˆ—表" #: src/view/com/lists/ListCard.tsx:91 #: src/view/com/modals/UserAddRemoveLists.tsx:204 -#: src/view/screens/ProfileList.tsx:772 +#: src/view/screens/ProfileList.tsx:773 msgid "Moderation list by you" -msgstr "é™åˆ¶åˆ—è¡¨ç”±ä½ åˆ›å»º" +msgstr "ä½ åˆ›å»ºçš„é™åˆ¶åˆ—表" #: src/view/com/modals/CreateOrEditList.tsx:197 msgid "Moderation list created" @@ -2269,7 +2287,7 @@ msgstr "é™åˆ¶åˆ—表已更新" msgid "Moderation lists" msgstr "é™åˆ¶åˆ—表" -#: src/Navigation.tsx:120 +#: src/Navigation.tsx:122 #: src/view/screens/ModerationModlists.tsx:58 msgid "Moderation Lists" msgstr "é™åˆ¶åˆ—表" @@ -2282,7 +2300,7 @@ msgstr "é™åˆ¶è®¾ç½®" msgid "Moderator has chosen to set a general warning on the content." msgstr "é™åˆ¶é€‰æ‹©å¯¹å†…容设置一般è¦å‘Šã€‚" -#: src/view/shell/desktop/Feeds.tsx:63 +#: src/view/shell/desktop/Feeds.tsx:65 msgid "More feeds" msgstr "æ›´å¤šä¿¡æ¯æµ" @@ -2293,24 +2311,24 @@ msgid "More options" msgstr "更多选项" #: src/view/com/util/forms/PostDropdownBtn.tsx:315 -msgid "More post options" -msgstr "更多帖å选项" +#~ msgid "More post options" +#~ msgstr "更多帖å选项" #: src/view/screens/PreferencesThreads.tsx:82 msgid "Most-liked replies first" -msgstr "最多点赞优先" +msgstr "优先显示最多喜欢" #: src/view/com/auth/create/Step2.tsx:122 msgid "Must be at least 3 characters" -msgstr "" +msgstr "需è¦è‡³å°‘ 3 个å—符" -#: src/components/TagMenu/index.tsx:253 +#: src/components/TagMenu/index.tsx:249 msgid "Mute" -msgstr "" +msgstr "éšè—" -#: src/components/TagMenu/index.web.tsx:91 +#: src/components/TagMenu/index.web.tsx:105 msgid "Mute {truncatedTag}" -msgstr "" +msgstr "éšè— {truncatedTag}" #: src/view/com/profile/ProfileHeader.tsx:327 msgid "Mute Account" @@ -2320,17 +2338,21 @@ msgstr "éšè—账户" msgid "Mute accounts" msgstr "éšè—账户" +#: src/components/TagMenu/index.tsx:209 +msgid "Mute all {displayTag} posts" +msgstr "éšè—所有 {displayTag} 的帖å" + #: src/components/TagMenu/index.tsx:211 -msgid "Mute all {tag} posts" -msgstr "" +#~ msgid "Mute all {tag} posts" +#~ msgstr "éšè—所有 {tag} 的帖å" -#: src/components/dialogs/MutedWords.tsx:131 +#: src/components/dialogs/MutedWords.tsx:149 msgid "Mute in tags only" -msgstr "" +msgstr "ä»…éšè—è¯é¢˜æ ‡ç¾" -#: src/components/dialogs/MutedWords.tsx:116 +#: src/components/dialogs/MutedWords.tsx:134 msgid "Mute in text & tags" -msgstr "" +msgstr "éšè—文本和è¯é¢˜æ ‡ç¾" #: src/view/screens/ProfileList.tsx:491 msgid "Mute list" @@ -2344,21 +2366,23 @@ msgstr "éšè—这些账户?" msgid "Mute this List" msgstr "éšè—这个列表" -#: src/components/dialogs/MutedWords.tsx:109 +#: src/components/dialogs/MutedWords.tsx:127 msgid "Mute this word in post text and tags" -msgstr "" +msgstr "åœ¨å¸–åæ–‡æœ¬å’Œè¯é¢˜æ ‡ç¾ä¸éšè—该è¯" -#: src/components/dialogs/MutedWords.tsx:124 +#: src/components/dialogs/MutedWords.tsx:142 msgid "Mute this word in tags only" -msgstr "" +msgstr "仅在è¯é¢˜æ ‡ç¾ä¸éšè—该è¯" -#: src/view/com/util/forms/PostDropdownBtn.tsx:202 +#: src/view/com/util/forms/PostDropdownBtn.tsx:251 +#: src/view/com/util/forms/PostDropdownBtn.tsx:257 msgid "Mute thread" msgstr "éšè—讨论串" -#: src/view/com/util/forms/PostDropdownBtn.tsx:216 +#: src/view/com/util/forms/PostDropdownBtn.tsx:267 +#: src/view/com/util/forms/PostDropdownBtn.tsx:269 msgid "Mute words & tags" -msgstr "" +msgstr "éšè—è¯å’Œè¯é¢˜æ ‡ç¾" #: src/view/com/lists/ListCard.tsx:102 msgid "Muted" @@ -2368,7 +2392,7 @@ msgstr "å·²éšè—" msgid "Muted accounts" msgstr "å·²éšè—账户" -#: src/Navigation.tsx:125 +#: src/Navigation.tsx:127 #: src/view/screens/ModerationMutedAccounts.tsx:107 msgid "Muted Accounts" msgstr "å·²éšè—账户" @@ -2379,7 +2403,7 @@ msgstr "å·²éšè—的账户将ä¸ä¼šåœ¨ä½ çš„é€šçŸ¥æˆ–æ—¶é—´çº¿ä¸æ˜¾ç¤ºï¼Œè¢«éš #: src/view/screens/Moderation.tsx:100 msgid "Muted words & tags" -msgstr "" +msgstr "å·²éšè—è¯å’Œè¯é¢˜æ ‡ç¾" #: src/view/screens/ProfileList.tsx:277 msgid "Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them." @@ -2395,7 +2419,7 @@ msgstr "è‡ªå®šä¹‰ä¿¡æ¯æµ" #: src/view/shell/desktop/LeftNav.tsx:65 msgid "My Profile" -msgstr "个人资料" +msgstr "我的个人资料" #: src/view/screens/Settings/index.tsx:582 msgid "My Saved Feeds" @@ -2403,7 +2427,7 @@ msgstr "我ä¿å˜çš„ä¿¡æ¯æµ" #: src/view/com/auth/server-input/index.tsx:118 msgid "my-server.com" -msgstr "" +msgstr "my-server.com" #: src/view/com/modals/AddAppPasswords.tsx:179 #: src/view/com/modals/CreateOrEditList.tsx:290 @@ -2444,9 +2468,9 @@ msgstr "永远ä¸ä¼šå¤±åŽ»å¯¹ä½ çš„å…³æ³¨è€…å’Œæ•°æ®çš„访问。" msgid "Never lose access to your followers or data." msgstr "永远ä¸ä¼šå¤±åŽ»å¯¹ä½ çš„å…³æ³¨è€…æˆ–æ•°æ®çš„访问。" -#: src/components/dialogs/MutedWords.tsx:244 +#: src/components/dialogs/MutedWords.tsx:293 msgid "Nevermind" -msgstr "" +msgstr "放弃" #: src/view/screens/Lists.tsx:76 msgctxt "action" @@ -2495,7 +2519,7 @@ msgstr "新的用户列表" #: src/view/screens/PreferencesThreads.tsx:79 msgid "Newest replies first" -msgstr "最新回å¤ä¼˜å…ˆ" +msgstr "优先显示最新回å¤" #: src/screens/Onboarding/index.tsx:23 msgid "News" @@ -2511,12 +2535,12 @@ msgstr "æ–°é—»" #: src/view/com/modals/ChangePassword.tsx:251 #: src/view/com/modals/ChangePassword.tsx:253 msgid "Next" -msgstr "下一个" +msgstr "下一æ¥" #: src/view/com/auth/onboarding/WelcomeDesktop.tsx:103 msgctxt "action" msgid "Next" -msgstr "下一个" +msgstr "下一æ¥" #: src/view/com/lightbox/Lightbox.web.tsx:149 msgid "Next image" @@ -2532,7 +2556,7 @@ msgid "No" msgstr "åœç”¨" #: src/view/screens/ProfileFeed.tsx:584 -#: src/view/screens/ProfileList.tsx:754 +#: src/view/screens/ProfileList.tsx:755 msgid "No description" msgstr "没有æè¿°" @@ -2542,13 +2566,17 @@ msgstr "ä¸å†å…³æ³¨ {0}" #: src/view/com/notifications/Feed.tsx:109 msgid "No notifications yet!" -msgstr "没有通知ï¼" +msgstr "还没有通知ï¼" #: src/view/com/composer/text-input/mobile/Autocomplete.tsx:97 #: src/view/com/composer/text-input/web/Autocomplete.tsx:191 msgid "No result" msgstr "没有结果" +#: src/components/Lists.tsx:192 +msgid "No results found" +msgstr "未找到结果" + #: src/view/screens/Feeds.tsx:495 msgid "No results found for \"{query}\"" msgstr "未找到\"{query}\"的结果" @@ -2571,7 +2599,7 @@ msgstr "没有人" msgid "Not Applicable." msgstr "ä¸é€‚用。" -#: src/Navigation.tsx:105 +#: src/Navigation.tsx:107 #: src/view/screens/Profile.tsx:106 msgid "Not Found" msgstr "未找到" @@ -2579,13 +2607,13 @@ msgstr "未找到" #: src/view/com/modals/VerifyEmail.tsx:246 #: src/view/com/modals/VerifyEmail.tsx:252 msgid "Not right now" -msgstr "䏿˜¯çŽ°åœ¨" +msgstr "暂时ä¸éœ€è¦" #: src/view/screens/Moderation.tsx:252 msgid "Note: Bluesky is an open and public network. This setting only limits the visibility of your content on the Bluesky app and website, and other apps may not respect this setting. Your content may still be shown to logged-out users by other apps and websites." msgstr "注æ„:Bluesky 是一个开放的公共网络。æ¤è®¾ç½®é¡¹ä»…é™åˆ¶ä½ 的内容在 Bluesky 应用和网站上的å¯è§æ€§ï¼Œå…¶ä»–应用å¯èƒ½ä¸å°Šä»Žæ¤è®¾ç½®é¡¹ï¼Œä»å¯èƒ½ä¼šå‘æœªç™»å½•çš„ç”¨æˆ·æ˜¾ç¤ºä½ çš„åŠ¨æ€ã€‚" -#: src/Navigation.tsx:450 +#: src/Navigation.tsx:457 #: src/view/screens/Notifications.tsx:124 #: src/view/screens/Notifications.tsx:148 #: src/view/shell/bottom-bar/BottomBar.tsx:205 @@ -2613,7 +2641,7 @@ msgstr "好的" #: src/view/screens/PreferencesThreads.tsx:78 msgid "Oldest replies first" -msgstr "最旧的回å¤ä¼˜å…ˆ" +msgstr "优先显示最旧的回å¤" #: src/view/screens/Settings/index.tsx:234 msgid "Onboarding reset" @@ -2627,6 +2655,11 @@ msgstr "è‡³å°‘æœ‰ä¸€å¼ å›¾ç‰‡ç¼ºå¤±äº†æ›¿ä»£æ–‡å—。" msgid "Only {0} can reply." msgstr "åªæœ‰ {0} å¯ä»¥å›žå¤ã€‚" +#: src/components/Lists.tsx:82 +msgid "Oops, something went wrong!" +msgstr "糟糕,å‘生了一些错误ï¼" + +#: src/components/Lists.tsx:188 #: src/view/screens/AppPasswords.tsx:65 #: src/view/screens/Profile.tsx:106 msgid "Oops!" @@ -2634,16 +2667,16 @@ msgstr "Oopsï¼" #: src/screens/Onboarding/StepFinished.tsx:115 msgid "Open" -msgstr "打开" +msgstr "å¼€å¯" #: src/view/screens/Moderation.tsx:75 msgid "Open content filtering settings" -msgstr "" +msgstr "打开内容过滤设置" #: src/view/com/composer/Composer.tsx:477 #: src/view/com/composer/Composer.tsx:478 msgid "Open emoji picker" -msgstr "打开 emoji 选择器" +msgstr "打开表情符å·é€‰æ‹©å™¨" #: src/view/screens/Settings/index.tsx:712 msgid "Open links with in-app browser" @@ -2651,112 +2684,116 @@ msgstr "在内置æµè§ˆå™¨ä¸æ‰“开链接" #: src/view/screens/Moderation.tsx:92 msgid "Open muted words settings" -msgstr "" +msgstr "打开éšè—è¯è®¾ç½®" -#: src/view/com/home/HomeHeaderLayoutMobile.tsx:49 +#: src/view/com/home/HomeHeaderLayoutMobile.tsx:50 msgid "Open navigation" -msgstr "打开导航" +msgstr "å¼€å¯å¯¼èˆª" + +#: src/view/com/util/forms/PostDropdownBtn.tsx:175 +msgid "Open post options menu" +msgstr "打开帖å选项èœå•" #: src/view/screens/Settings/index.tsx:804 msgid "Open storybook page" -msgstr "打开故事书界é¢" +msgstr "å¼€å¯ Storybook 界é¢" #: src/view/com/util/forms/DropdownButton.tsx:154 msgid "Opens {numItems} options" -msgstr "打开 {numItems} 个选项" +msgstr "å¼€å¯ {numItems} 个选项" #: src/view/screens/Log.tsx:54 msgid "Opens additional details for a debug entry" -msgstr "æ‰“å¼€è°ƒè¯•è®°å½•çš„é™„åŠ è¯¦ç»†ä¿¡æ¯" +msgstr "å¼€å¯è°ƒè¯•记录的é¢å¤–详细信æ¯" -#: src/view/com/notifications/FeedItem.tsx:348 +#: src/view/com/notifications/FeedItem.tsx:349 msgid "Opens an expanded list of users in this notification" -msgstr "打开æ¤é€šçŸ¥ä¸çš„æ‰©å±•用户列表" +msgstr "展开æ¤é€šçŸ¥ä¸çš„æ‰©å±•用户列表" #: src/view/com/composer/photos/OpenCameraBtn.tsx:61 msgid "Opens camera on device" -msgstr "打开设备相机" +msgstr "å¼€å¯è®¾å¤‡ç›¸æœº" #: src/view/com/composer/Prompt.tsx:25 msgid "Opens composer" -msgstr "打开编辑器" +msgstr "å¼€å¯ç¼–辑器" #: src/view/screens/Settings/index.tsx:595 msgid "Opens configurable language settings" -msgstr "打开å¯é…置的è¯è¨€è®¾ç½®" +msgstr "å¼€å¯å¯é…置的è¯è¨€è®¾ç½®" #: src/view/com/composer/photos/SelectPhotoBtn.tsx:44 msgid "Opens device photo gallery" -msgstr "打开设备相册" +msgstr "å¼€å¯è®¾å¤‡ç›¸å†Œ" #: src/view/com/profile/ProfileHeader.tsx:420 msgid "Opens editor for profile display name, avatar, background image, and description" -msgstr "打开个人资料(如åç§°ã€å¤´åƒã€èƒŒæ™¯å›¾ç‰‡ã€æè¿°ç‰ï¼‰ç¼–辑器" +msgstr "å¼€å¯ä¸ªäººèµ„料(如åç§°ã€å¤´åƒã€èƒŒæ™¯å›¾ç‰‡ã€æè¿°ç‰ï¼‰ç¼–辑器" #: src/view/screens/Settings/index.tsx:649 msgid "Opens external embeds settings" -msgstr "打开外部嵌入设置" +msgstr "å¼€å¯å¤–部嵌入设置" #: src/view/com/profile/ProfileHeader.tsx:575 msgid "Opens followers list" -msgstr "打开关注者列表" +msgstr "å¼€å¯å…³æ³¨è€…列表" #: src/view/com/profile/ProfileHeader.tsx:594 msgid "Opens following list" -msgstr "打开æ£åœ¨å…³æ³¨åˆ—表" +msgstr "开坿£åœ¨å…³æ³¨åˆ—表" #: src/view/screens/Settings.tsx:412 #~ msgid "Opens invite code list" -#~ msgstr "打开邀请ç 列表" +#~ msgstr "å¼€å¯é‚€è¯·ç 列表" #: src/view/com/modals/InviteCodes.tsx:172 msgid "Opens list of invite codes" -msgstr "打开邀请ç 列表" +msgstr "å¼€å¯é‚€è¯·ç 列表" #: src/view/screens/Settings/index.tsx:774 msgid "Opens modal for account deletion confirmation. Requires email code." -msgstr "æ‰“å¼€ç”¨æˆ·åˆ é™¤ç¡®è®¤ç•Œé¢ï¼Œéœ€è¦ç”µå邮箱接收验è¯ç 。" +msgstr "å¼€å¯ç”¨æˆ·åˆ 除确认界é¢ï¼Œéœ€è¦ç”µå邮箱接收验è¯ç 。" #: src/view/com/modals/ChangeHandle.tsx:281 msgid "Opens modal for using custom domain" -msgstr "打开使用自定义域å的模å¼" +msgstr "å¼€å¯ä½¿ç”¨è‡ªå®šä¹‰åŸŸå的模å¼" #: src/view/screens/Settings/index.tsx:620 msgid "Opens moderation settings" -msgstr "打开é™åˆ¶è®¾ç½®" +msgstr "å¼€å¯é™åˆ¶è®¾ç½®" #: src/view/com/auth/login/LoginForm.tsx:239 msgid "Opens password reset form" -msgstr "打开密ç é‡ç½®ç”³è¯·" +msgstr "å¼€å¯å¯†ç é‡ç½®ç”³è¯·" -#: src/view/com/home/HomeHeaderLayout.web.tsx:60 +#: src/view/com/home/HomeHeaderLayout.web.tsx:63 #: src/view/screens/Feeds.tsx:356 msgid "Opens screen to edit Saved Feeds" -msgstr "打开用于编辑已ä¿å˜ä¿¡æ¯æµçš„界é¢" +msgstr "å¼€å¯ç”¨äºŽç¼–辑已ä¿å˜ä¿¡æ¯æµçš„界é¢" #: src/view/screens/Settings/index.tsx:576 msgid "Opens screen with all saved feeds" -msgstr "æ‰“å¼€åŒ…å«æ‰€æœ‰å·²ä¿å˜ä¿¡æ¯æµçš„界é¢" +msgstr "å¼€å¯åŒ…嫿‰€æœ‰å·²ä¿å˜ä¿¡æ¯æµçš„界é¢" #: src/view/screens/Settings/index.tsx:676 msgid "Opens the app password settings page" -msgstr "打开 App 专用密ç 设置页" +msgstr "å¼€å¯åº”用专用密ç 设置页" #: src/view/screens/Settings/index.tsx:535 msgid "Opens the home feed preferences" -msgstr "æ‰“å¼€ä¸»é¡µä¿¡æ¯æµé¦–选项" +msgstr "å¼€å¯ä¸»é¡µä¿¡æ¯æµé¦–选项" #: src/view/screens/Settings/index.tsx:805 msgid "Opens the storybook page" -msgstr "打开故事书界é¢" +msgstr "å¼€å¯ Storybook 界é¢" #: src/view/screens/Settings/index.tsx:793 msgid "Opens the system log page" -msgstr "打开系统日志界é¢" +msgstr "å¼€å¯ç³»ç»Ÿæ—¥å¿—界é¢" #: src/view/screens/Settings/index.tsx:556 msgid "Opens the threads preferences" -msgstr "打开讨论串首选项" +msgstr "å¼€å¯è®¨è®ºä¸²é¦–选项" #: src/view/com/util/forms/DropdownButton.tsx:280 msgid "Option {0} of {numItems}" @@ -2778,6 +2815,7 @@ msgstr "其他账户" msgid "Other..." msgstr "å…¶ä»–..." +#: src/components/Lists.tsx:194 #: src/view/screens/NotFound.tsx:45 msgid "Page not found" msgstr "æ— æ³•æ‰¾åˆ°æ¤é¡µé¢" @@ -2786,8 +2824,8 @@ msgstr "æ— æ³•æ‰¾åˆ°æ¤é¡µé¢" msgid "Page Not Found" msgstr "æ— æ³•æ‰¾åˆ°æ¤é¡µé¢" -#: src/view/com/auth/create/Step1.tsx:214 -#: src/view/com/auth/create/Step1.tsx:224 +#: src/view/com/auth/create/Step1.tsx:191 +#: src/view/com/auth/create/Step1.tsx:201 #: src/view/com/auth/login/LoginForm.tsx:226 #: src/view/com/auth/login/SetNewPasswordForm.tsx:161 #: src/view/com/modals/DeleteAccount.tsx:202 @@ -2802,13 +2840,13 @@ msgstr "密ç 已更新" msgid "Password updated!" msgstr "密ç 已更新ï¼" -#: src/Navigation.tsx:160 +#: src/Navigation.tsx:162 msgid "People followed by @{0}" -msgstr "被这些人所关注 @{0}" +msgstr "@{0} 关注的人" -#: src/Navigation.tsx:153 +#: src/Navigation.tsx:155 msgid "People following @{0}" -msgstr "æ£åœ¨å…³æ³¨ @{0}" +msgstr "关注 @{0} 的人" #: src/view/com/lightbox/Lightbox.tsx:66 msgid "Permission to access camera roll is required." @@ -2862,15 +2900,15 @@ msgstr "è¯·è®¾ç½®ä½ çš„å¯†ç 。" #: src/view/com/auth/create/state.ts:131 msgid "Please complete the verification captcha." -msgstr "" +msgstr "è¯·å®Œæˆ Captcha 验è¯" #: src/view/com/modals/ChangeEmail.tsx:67 msgid "Please confirm your email before changing it. This is a temporary requirement while email-updating tools are added, and it will soon be removed." -msgstr "更改å‰è¯·å…ˆç¡®è®¤ä½ 的电åé‚®ç®±ã€‚è¿™æ˜¯æ·»åŠ ç”µåé‚®ç®±æ›´æ–°å·¥å…·çš„ä¸´æ—¶è¦æ±‚,æ¤é™åˆ¶å°†å¾ˆå¿«è¢«ç§»é™¤ã€‚" +msgstr "更改å‰è¯·å…ˆç¡®è®¤ä½ 的电å邮箱。这是新增电åé‚®ç®±æ›´æ–°å·¥å…·çš„ä¸´æ—¶è¦æ±‚,æ¤é™åˆ¶å°†å¾ˆå¿«è¢«ç§»é™¤ã€‚" #: src/view/com/modals/AddAppPasswords.tsx:90 msgid "Please enter a name for your app password. All spaces is not allowed." -msgstr "请输入 App 专用密ç çš„å称,ä¸å…è®¸ä½¿ç”¨ç©ºæ ¼ã€‚" +msgstr "请输入应用专用密ç çš„å称,ä¸å…è®¸ä½¿ç”¨ç©ºæ ¼ã€‚" #: src/view/com/auth/create/Step2.tsx:206 #~ msgid "Please enter a phone number that can receive SMS text messages." @@ -2878,7 +2916,11 @@ msgstr "请输入 App 专用密ç çš„å称,ä¸å…è®¸ä½¿ç”¨ç©ºæ ¼ã€‚" #: src/view/com/modals/AddAppPasswords.tsx:145 msgid "Please enter a unique name for this App Password or use our randomly generated one." -msgstr "è¯·è¾“å…¥æ¤ App 专用密ç 的唯一å称,或使用我们æä¾›çš„éšæœºç”Ÿæˆå称。" +msgstr "请输入æ¤åº”用专用密ç 的唯一å称,或使用我们æä¾›çš„éšæœºç”Ÿæˆå称。" + +#: src/components/dialogs/MutedWords.tsx:68 +msgid "Please enter a valid word, tag, or phrase to mute" +msgstr "请输入一个有效的è¯ã€è¯é¢˜æ ‡ç¾æˆ–çŸè¯" #: src/view/com/auth/create/state.ts:170 #~ msgid "Please enter the code you received by SMS." @@ -2907,7 +2949,7 @@ msgstr "请验è¯ä½ 的电å邮箱" #: src/view/com/composer/Composer.tsx:222 msgid "Please wait for your link card to finish loading" -msgstr "请ç‰å¾…ä½ çš„é“¾æŽ¥å¡ç‰‡åŠ è½½å®Œæˆ" +msgstr "请ç‰å¾…ä½ çš„é“¾æŽ¥å¡ç‰‡åŠ è½½å®Œæ¯•" #: src/screens/Onboarding/index.tsx:37 msgid "Politics" @@ -2930,15 +2972,15 @@ msgstr "å‘布" #: src/view/com/post-thread/PostThreadItem.tsx:175 msgid "Post by {0}" -msgstr "å‘布者 {0}" +msgstr "{0} 的帖å" -#: src/Navigation.tsx:172 -#: src/Navigation.tsx:179 -#: src/Navigation.tsx:186 +#: src/Navigation.tsx:174 +#: src/Navigation.tsx:181 +#: src/Navigation.tsx:188 msgid "Post by @{0}" -msgstr "å‘布者 @{0}" +msgstr "@{0} 的帖å" -#: src/view/com/util/forms/PostDropdownBtn.tsx:90 +#: src/view/com/util/forms/PostDropdownBtn.tsx:108 msgid "Post deleted" msgstr "å·²åˆ é™¤å¸–å" @@ -2958,21 +3000,21 @@ msgstr "帖åè¯è¨€" msgid "Post not found" msgstr "æ— æ³•æ‰¾åˆ°å¸–å" -#: src/components/TagMenu/index.tsx:257 +#: src/components/TagMenu/index.tsx:253 msgid "posts" -msgstr "" +msgstr "帖å" #: src/view/screens/Profile.tsx:180 msgid "Posts" msgstr "帖å" -#: src/components/dialogs/MutedWords.tsx:77 +#: src/components/dialogs/MutedWords.tsx:90 msgid "Posts can be muted based on their text, their tags, or both." -msgstr "" +msgstr "帖åå¯ä»¥æ ¹æ®å…¶æ–‡æœ¬ã€è¯é¢˜æ ‡ç¾æˆ–两者æ¥éšè—。" #: src/view/com/posts/FeedErrorMessage.tsx:64 msgid "Posts hidden" -msgstr "å·²éšè—帖å" +msgstr "帖åå·²éšè—" #: src/view/com/modals/LinkWarning.tsx:46 msgid "Potentially Misleading Link" @@ -2988,14 +3030,14 @@ msgstr "首选è¯è¨€" #: src/view/screens/PreferencesThreads.tsx:97 msgid "Prioritize Your Follows" -msgstr "关注者优先" +msgstr "优先显示关注者" #: src/view/screens/Settings/index.tsx:632 #: src/view/shell/desktop/RightNav.tsx:72 msgid "Privacy" msgstr "éšç§" -#: src/Navigation.tsx:217 +#: src/Navigation.tsx:219 #: src/view/screens/PrivacyPolicy.tsx:29 #: src/view/screens/Settings/index.tsx:891 #: src/view/shell/Drawer.tsx:262 @@ -3012,11 +3054,11 @@ msgstr "处ç†ä¸..." #: src/view/shell/Drawer.tsx:546 #: src/view/shell/Drawer.tsx:547 msgid "Profile" -msgstr "资料" +msgstr "个人资料" #: src/view/com/modals/EditProfile.tsx:128 msgid "Profile updated" -msgstr "资料已更新" +msgstr "个人资料已更新" #: src/view/screens/Settings/index.tsx:949 msgid "Protect your account by verifying your email." @@ -3058,7 +3100,7 @@ msgstr "引用帖å" #: src/view/screens/PreferencesThreads.tsx:86 msgid "Random (aka \"Poster's Roulette\")" -msgstr "ä»¥éšæœºé¡ºåºæ˜¾ç¤º (åˆå试试手气)" +msgstr "éšæœºæ˜¾ç¤º (手气ä¸é”™)" #: src/view/com/modals/EditImage.tsx:236 msgid "Ratios" @@ -3072,14 +3114,14 @@ msgstr "推èä¿¡æ¯æµ" msgid "Recommended Users" msgstr "推è的用户" -#: src/components/dialogs/MutedWords.tsx:249 +#: src/components/dialogs/MutedWords.tsx:298 #: src/view/com/modals/ListAddRemoveUsers.tsx:264 #: src/view/com/modals/SelfLabel.tsx:83 #: src/view/com/modals/UserAddRemoveLists.tsx:219 #: src/view/com/util/UserAvatar.tsx:285 #: src/view/com/util/UserBanner.tsx:91 msgid "Remove" -msgstr "åˆ é™¤" +msgstr "移除" #: src/view/com/feeds/FeedSourceCard.tsx:108 msgid "Remove {0} from my feeds?" @@ -3110,9 +3152,9 @@ msgstr "åˆ é™¤å›¾ç‰‡" msgid "Remove image preview" msgstr "åˆ é™¤å›¾ç‰‡é¢„è§ˆ" -#: src/components/dialogs/MutedWords.tsx:294 +#: src/components/dialogs/MutedWords.tsx:343 msgid "Remove mute word from your list" -msgstr "" +msgstr "ä»Žä½ çš„éšè—è¯åˆ—表ä¸åˆ 除" #: src/view/com/modals/Repost.tsx:47 msgid "Remove repost" @@ -3180,7 +3222,8 @@ msgid "Report List" msgstr "举报列表" #: src/view/com/modals/report/SendReportButton.tsx:37 -#: src/view/com/util/forms/PostDropdownBtn.tsx:255 +#: src/view/com/util/forms/PostDropdownBtn.tsx:301 +#: src/view/com/util/forms/PostDropdownBtn.tsx:309 msgid "Report post" msgstr "举报帖å" @@ -3237,20 +3280,20 @@ msgstr "确认ç " #: src/view/screens/Settings/index.tsx:456 msgid "Require alt text before posting" -msgstr "è¦æ±‚å‘å¸ƒå‰æä¾›æ›¿ä»£æ–‡æœ¬" +msgstr "å‘布时检查媒体是å¦å˜åœ¨æ›¿ä»£æ–‡æœ¬" -#: src/view/com/auth/create/Step1.tsx:153 +#: src/view/com/auth/create/Step1.tsx:146 msgid "Required for this provider" -msgstr "应æä¾›å•†è¦æ±‚" +msgstr "æœåŠ¡æä¾›è€…è¦æ±‚" #: src/view/com/auth/login/SetNewPasswordForm.tsx:124 #: src/view/com/auth/login/SetNewPasswordForm.tsx:136 msgid "Reset code" -msgstr "é‡ç½®ç " +msgstr "确认ç " #: src/view/com/modals/ChangePassword.tsx:190 msgid "Reset Code" -msgstr "é‡ç½®ä»£ç " +msgstr "确认ç " #: src/view/screens/Settings/index.tsx:824 msgid "Reset onboarding" @@ -3304,7 +3347,7 @@ msgstr "é‡è¯•" #~ msgid "Retry." #~ msgstr "é‡è¯•。" -#: src/view/screens/ProfileList.tsx:898 +#: src/view/screens/ProfileList.tsx:903 msgid "Return to previous page" msgstr "回到上一页" @@ -3337,7 +3380,7 @@ msgstr "ä¿å˜æ›´æ”¹" #: src/view/com/modals/ChangeHandle.tsx:170 msgid "Save handle change" -msgstr "ä¿å˜æ–°çš„用户识别符" +msgstr "ä¿å˜ç”¨æˆ·è¯†åˆ«ç¬¦æ›´æ”¹" #: src/view/com/modals/crop-image/CropImage.web.tsx:144 msgid "Save image crop" @@ -3359,11 +3402,11 @@ msgstr "ä¿å˜ç”¨æˆ·è¯†åˆ«ç¬¦æ›´æ”¹è‡³ {handle}" msgid "Science" msgstr "ç§‘å¦" -#: src/view/screens/ProfileList.tsx:854 +#: src/view/screens/ProfileList.tsx:859 msgid "Scroll to top" msgstr "滚动到顶部" -#: src/Navigation.tsx:440 +#: src/Navigation.tsx:447 #: src/view/com/auth/LoggedOut.tsx:122 #: src/view/com/modals/ListAddRemoveUsers.tsx:75 #: src/view/com/util/forms/SearchInput.tsx:67 @@ -3386,12 +3429,20 @@ msgid "Search for \"{query}\"" msgstr "æœç´¢ \"{query}\"" #: src/components/TagMenu/index.tsx:145 -msgid "Search for all posts by @{authorHandle} with tag {tag}" -msgstr "" +msgid "Search for all posts by @{authorHandle} with tag {displayTag}" +msgstr "æœç´¢ @{authorHandle} 带有 {displayTag} 的所有帖å" + +#: src/components/TagMenu/index.tsx:145 +#~ msgid "Search for all posts by @{authorHandle} with tag {tag}" +#~ msgstr "æœç´¢ @{authorHandle} 带有 {tag} 的所有帖å" + +#: src/components/TagMenu/index.tsx:94 +msgid "Search for all posts with tag {displayTag}" +msgstr "æœç´¢æ‰€æœ‰å¸¦æœ‰ {displayTag} 的帖å" #: src/components/TagMenu/index.tsx:90 -msgid "Search for all posts with tag {tag}" -msgstr "" +#~ msgid "Search for all posts with tag {tag}" +#~ msgstr "æœç´¢æ‰€æœ‰å¸¦æœ‰ {tag} 的帖å" #: src/view/com/auth/LoggedOut.tsx:104 #: src/view/com/auth/LoggedOut.tsx:105 @@ -3403,21 +3454,29 @@ msgstr "æœç´¢ç”¨æˆ·" msgid "Security Step Required" msgstr "所需的安全æ¥éª¤" -#: src/components/TagMenu/index.web.tsx:50 +#: src/components/TagMenu/index.web.tsx:66 msgid "See {truncatedTag} posts" -msgstr "" +msgstr "查看 {truncatedTag} 的帖å" -#: src/components/TagMenu/index.web.tsx:67 +#: src/components/TagMenu/index.web.tsx:83 msgid "See {truncatedTag} posts by user" -msgstr "" +msgstr "按用户查看 {truncatedTag} 的帖å" #: src/components/TagMenu/index.tsx:128 -msgid "See <0>{tag}</0> posts" -msgstr "" +msgid "See <0>{displayTag}</0> posts" +msgstr "查看 <0>{displayTag}</0> 的帖å" + +#: src/components/TagMenu/index.tsx:187 +msgid "See <0>{displayTag}</0> posts by this user" +msgstr "查看该用户 <0>{displayTag}</0> 的帖å" + +#: src/components/TagMenu/index.tsx:128 +#~ msgid "See <0>{tag}</0> posts" +#~ msgstr "查看 <0>{tag}</0> 的帖å" #: src/components/TagMenu/index.tsx:189 -msgid "See <0>{tag}</0> posts by this user" -msgstr "" +#~ msgid "See <0>{tag}</0> posts by this user" +#~ msgstr "查看该用户 <0>{tag}</0> 的帖å" #: src/view/screens/SavedFeeds.tsx:163 msgid "See this guide" @@ -3437,13 +3496,13 @@ msgstr "选择 {item}" #: src/view/com/auth/login/Login.tsx:117 msgid "Select from an existing account" -msgstr "选择已å˜åœ¨çš„账户" +msgstr "从现有账户ä¸é€‰æ‹©" #: src/view/com/util/Selector.tsx:107 msgid "Select option {i} of {numItems}" -msgstr "从 {i} 项ä¸é€‰æ‹© {numItems} 项" +msgstr "选择 {numItems} 项ä¸çš„第 {i} 项" -#: src/view/com/auth/create/Step1.tsx:103 +#: src/view/com/auth/create/Step1.tsx:96 #: src/view/com/auth/login/LoginForm.tsx:150 msgid "Select service" msgstr "选择æœåŠ¡" @@ -3454,7 +3513,7 @@ msgstr "选择以下一些账户进行关注" #: src/view/com/auth/server-input/index.tsx:82 msgid "Select the service that hosts your data." -msgstr "" +msgstr "é€‰æ‹©æ‰˜ç®¡ä½ æ•°æ®çš„æœåŠ¡å™¨ã€‚" #: src/screens/Onboarding/StepTopicalFeeds.tsx:96 msgid "Select topical feeds to follow from the list below" @@ -3517,11 +3576,11 @@ msgstr "æäº¤ä¸¾æŠ¥" #: src/view/com/modals/DeleteAccount.tsx:133 msgid "Sends email with confirmation code for account deletion" -msgstr "å‘é€åŒ…å«è´¦æˆ·åˆ 除确认ç 的电å邮件" +msgstr "å‘é€åŒ…å«è´¦æˆ·åˆ 除验è¯ç 的电å邮件" #: src/view/com/auth/server-input/index.tsx:110 msgid "Server address" -msgstr "" +msgstr "æœåŠ¡å™¨åœ°å€" #: src/view/com/modals/ContentFilteringSettings.tsx:311 msgid "Set {value} for {labelGroup} content moderation policy" @@ -3557,7 +3616,7 @@ msgstr "设置深色模å¼è‡³æš—æ·¡" msgid "Set new password" msgstr "设置新密ç " -#: src/view/com/auth/create/Step1.tsx:225 +#: src/view/com/auth/create/Step1.tsx:202 msgid "Set password" msgstr "设置密ç " @@ -3583,7 +3642,7 @@ msgstr "å¯ç”¨æ¤è®¾ç½®é¡¹ä»¥åœ¨åˆ†å±‚è§†å›¾ä¸æ˜¾ç¤ºå›žå¤ã€‚这是一个实验 #: src/view/screens/PreferencesFollowingFeed.tsx:261 msgid "Set this setting to \"Yes\" to show samples of your saved feeds in your Following feed. This is an experimental feature." -msgstr "" +msgstr "å¯ç”¨æ¤è®¾ç½®é¡¹ä»¥åœ¨å…³æ³¨ä¿¡æ¯æµä¸æ˜¾ç¤ºå·²ä¿å˜ä¿¡æ¯æµçš„æ ·ä¾‹ã€‚这是一个实验性功能。" #: src/screens/Onboarding/Layout.tsx:50 msgid "Set up your account" @@ -3601,12 +3660,12 @@ msgstr "设置用于é‡ç½®å¯†ç 的电å邮箱" msgid "Sets hosting provider for password reset" msgstr "设置用于密ç é‡ç½®çš„æ‰˜ç®¡æä¾›å•†ä¿¡æ¯" -#: src/view/com/auth/create/Step1.tsx:104 +#: src/view/com/auth/create/Step1.tsx:97 #: src/view/com/auth/login/LoginForm.tsx:151 msgid "Sets server for the Bluesky client" msgstr "设置 Bluesky 客户端的æœåС噍" -#: src/Navigation.tsx:135 +#: src/Navigation.tsx:137 #: src/view/screens/Settings/index.tsx:294 #: src/view/shell/desktop/LeftNav.tsx:433 #: src/view/shell/Drawer.tsx:567 @@ -3624,7 +3683,9 @@ msgid "Share" msgstr "分享" #: src/view/com/profile/ProfileHeader.tsx:295 -#: src/view/com/util/forms/PostDropdownBtn.tsx:184 +#: src/view/com/util/forms/PostDropdownBtn.tsx:231 +#: src/view/com/util/forms/PostDropdownBtn.tsx:237 +#: src/view/com/util/post-ctrls/PostCtrls.tsx:215 #: src/view/screens/ProfileList.tsx:418 msgid "Share" msgstr "分享" @@ -3701,7 +3762,7 @@ msgstr "åœ¨å…³æ³¨ä¿¡æ¯æµä¸æ˜¾ç¤ºå›žå¤" #: src/view/screens/PreferencesFollowingFeed.tsx:70 msgid "Show replies with at least {value} {0}" -msgstr "æ˜¾ç¤ºè‡³å°‘åŒ…å« {value} {0} 的回å¤" +msgstr "æ˜¾ç¤ºè‡³å°‘åŒ…å« {value} 个 {0} 的回å¤" #: src/view/screens/PreferencesFollowingFeed.tsx:188 msgid "Show Reposts" @@ -3716,7 +3777,7 @@ msgstr "åœ¨å…³æ³¨ä¸æ˜¾ç¤ºè½¬å‘" msgid "Show the content" msgstr "显示内容" -#: src/view/com/notifications/FeedItem.tsx:346 +#: src/view/com/notifications/FeedItem.tsx:347 msgid "Show users" msgstr "显示用户" @@ -3823,13 +3884,17 @@ msgstr "程åºå¼€å‘" #~ msgid "Something went wrong and we're not sure what." #~ msgstr "å‡ºäº†ç‚¹é—®é¢˜ï¼ŒåŽŸå› ä¸æ˜Žã€‚" +#: src/components/Lists.tsx:203 +msgid "Something went wrong!" +msgstr "出了点问题ï¼" + #: src/view/com/modals/Waitlist.tsx:51 -msgid "Something went wrong. Check your email and try again." -msgstr "å‡ºäº†ç‚¹é—®é¢˜ï¼Œè¯·æ£€æŸ¥ä½ çš„ç”µå邮箱并é‡è¯•。" +#~ msgid "Something went wrong. Check your email and try again." +#~ msgstr "å‡ºäº†ç‚¹é—®é¢˜ï¼Œè¯·æ£€æŸ¥ä½ çš„ç”µå邮箱并é‡è¯•。" -#: src/App.native.tsx:63 +#: src/App.native.tsx:66 msgid "Sorry! Your session expired. Please log in again." -msgstr "很抱æ‰ï¼Œä½ 的会è¯å·²è¿‡æœŸï¼Œè¯·é‡æ–°ç™»å½•。" +msgstr "很抱æ‰ï¼Œä½ 的登录会è¯å·²è¿‡æœŸï¼Œè¯·é‡æ–°ç™»å½•。" #: src/view/screens/PreferencesThreads.tsx:69 msgid "Sort Replies" @@ -3861,12 +3926,12 @@ msgstr "第 {0} æ¥ï¼Œå…± {numSteps} æ¥" #: src/view/screens/Settings/index.tsx:274 msgid "Storage cleared, you need to restart the app now." -msgstr "已清除å˜å‚¨ï¼Œè¯·ç«‹å³é‡å¯ App。" +msgstr "已清除å˜å‚¨ï¼Œè¯·ç«‹å³é‡å¯åº”用。" -#: src/Navigation.tsx:202 +#: src/Navigation.tsx:204 #: src/view/screens/Settings/index.tsx:807 msgid "Storybook" -msgstr "故事书" +msgstr "Storybook" #: src/view/com/modals/AppealLabel.tsx:101 msgid "Submit" @@ -3877,7 +3942,7 @@ msgid "Subscribe" msgstr "订阅" #: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:173 -#: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:307 +#: src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx:308 msgid "Subscribe to the {0} feed" msgstr "订阅 {0} ä¿¡æ¯æµ" @@ -3897,7 +3962,7 @@ msgstr "ä¸ºä½ æŽ¨è" msgid "Suggestive" msgstr "建议" -#: src/Navigation.tsx:212 +#: src/Navigation.tsx:214 #: src/view/screens/Support.tsx:30 #: src/view/screens/Support.tsx:33 msgid "Support" @@ -3929,13 +3994,17 @@ msgstr "系统" msgid "System log" msgstr "系统日志" -#: src/components/dialogs/MutedWords.tsx:288 +#: src/components/dialogs/MutedWords.tsx:337 msgid "tag" -msgstr "" +msgstr "è¯é¢˜æ ‡ç¾" + +#: src/components/TagMenu/index.tsx:78 +msgid "Tag menu: {displayTag}" +msgstr "è¯é¢˜æ ‡ç¾èœå•:{displayTag}" #: src/components/TagMenu/index.tsx:74 -msgid "Tag menu: {tag}" -msgstr "" +#~ msgid "Tag menu: {tag}" +#~ msgstr "è¯é¢˜æ ‡ç¾èœå•:{tag}" #: src/view/com/modals/crop-image/CropImage.web.tsx:112 msgid "Tall" @@ -3953,25 +4022,25 @@ msgstr "科技" msgid "Terms" msgstr "æ¡æ¬¾" -#: src/Navigation.tsx:222 +#: src/Navigation.tsx:224 #: src/view/screens/Settings/index.tsx:885 #: src/view/screens/TermsOfService.tsx:29 #: src/view/shell/Drawer.tsx:256 msgid "Terms of Service" msgstr "æœåŠ¡æ¡æ¬¾" -#: src/components/dialogs/MutedWords.tsx:288 +#: src/components/dialogs/MutedWords.tsx:337 msgid "text" -msgstr "" +msgstr "文本" #: src/view/com/modals/AppealLabel.tsx:70 #: src/view/com/modals/report/InputIssueDetails.tsx:51 msgid "Text input field" -msgstr "æ–‡æœ¬è¾“å…¥å—æ®µ" +msgstr "文本输入框" #: src/view/com/auth/create/CreateAccount.tsx:94 msgid "That handle is already taken." -msgstr "" +msgstr "该用户识别符已被å 用" #: src/view/com/profile/ProfileHeader.tsx:263 msgid "The account will be able to interact with you after unblocking." @@ -3991,7 +4060,7 @@ msgstr "以下æ¥éª¤å°†å¸®åŠ©å®šåˆ¶ä½ çš„ Bluesky 体验。" #: src/view/com/post-thread/PostThread.tsx:517 msgid "The post may have been deleted." -msgstr "æ¤å¸–åä¼¼ä¹Žå·²è¢«åˆ é™¤ã€‚" +msgstr "æ¤å¸–åå¯èƒ½å·²è¢«åˆ 除。" #: src/view/screens/PrivacyPolicy.tsx:33 msgid "The Privacy Policy has been moved to <0/>" @@ -3999,7 +4068,7 @@ msgstr "éšç§æ”¿ç–å·²è¿ç§»è‡³ <0/>" #: src/view/screens/Support.tsx:36 msgid "The support form has been moved. If you need help, please <0/> or visit {HELP_DESK_URL} to get in touch with us." -msgstr "支æŒè¡¨å•已移动ä½ç½®ã€‚å¦‚æžœä½ éœ€è¦å¸®åŠ©ï¼Œè¯·ç‚¹å‡»<0/>或访问{HELP_DESK_URL}与我们è”系。" +msgstr "支æŒè¡¨å•å·²è¢«ç§»é™¤ã€‚å¦‚æžœä½ éœ€è¦å¸®åŠ©ï¼Œè¯·ç‚¹å‡»<0/>或访问{HELP_DESK_URL}与我们è”系。" #: src/view/screens/TermsOfService.tsx:33 msgid "The Terms of Service have been moved to" @@ -4041,7 +4110,7 @@ msgstr "连接æœåŠ¡å™¨æ—¶å‡ºçŽ°é—®é¢˜" msgid "There was an issue fetching notifications. Tap here to try again." msgstr "刷新通知时出现问题,点击é‡è¯•。" -#: src/view/com/posts/Feed.tsx:263 +#: src/view/com/posts/Feed.tsx:265 msgid "There was an issue fetching posts. Tap here to try again." msgstr "åˆ·æ–°å¸–åæ—¶å‡ºçŽ°é—®é¢˜ï¼Œç‚¹å‡»é‡è¯•。" @@ -4061,7 +4130,7 @@ msgstr "与æœåŠ¡å™¨åŒæ¥é¦–选项时出现问题" #: src/view/screens/AppPasswords.tsx:66 msgid "There was an issue with fetching your app passwords" -msgstr "èŽ·å– App ä¸“ç”¨å¯†ç æ—¶å‡ºçŽ°é—®é¢˜" +msgstr "获å–åº”ç”¨ä¸“ç”¨å¯†ç æ—¶å‡ºçŽ°é—®é¢˜" #: src/view/com/post-thread/PostThreadFollowBtn.tsx:93 #: src/view/com/post-thread/PostThreadFollowBtn.tsx:105 @@ -4099,7 +4168,7 @@ msgstr "è¿™é‡Œæ˜¯ä¸€äº›å—æ¬¢è¿Žçš„è´¦å·ï¼Œä½ å¯èƒ½ä¼šå–œæ¬¢ï¼š" #: src/view/com/util/moderation/ScreenHider.tsx:88 msgid "This {screenDescription} has been flagged:" -msgstr "这个 {screenDescription} å·²è¢«æ ‡è®°ï¼š" +msgstr "{screenDescription} å·²è¢«æ ‡è®°ï¼š" #: src/view/com/util/moderation/ScreenHider.tsx:83 msgid "This account has requested that users sign in to view their profile." @@ -4119,7 +4188,7 @@ msgstr "没有 Bluesky è´¦æˆ·ï¼Œæ— æ³•æŸ¥çœ‹æ¤å†…容。" #: src/view/screens/Settings/ExportCarDialog.tsx:75 msgid "This feature is in beta. You can read more about repository exports in <0>this blogpost.</0>" -msgstr "" +msgstr "该功能æ£åœ¨æµ‹è¯•ã€‚ä½ å¯ä»¥åœ¨<0>这篇åšå®¢æ–‡ç« </0>ä¸èŽ·å¾—å…³äºŽå¯¼å‡ºæ•°æ®çš„æ›´å¤šä¿¡æ¯ã€‚" #: src/view/com/posts/FeedErrorMessage.tsx:114 msgid "This feed is currently receiving high traffic and is temporarily unavailable. Please try again later." @@ -4137,7 +4206,7 @@ msgstr "è¯¥ä¿¡æ¯æµä¸ºç©ºï¼ä½ 或许需è¦å…ˆå…³æ³¨æ›´å¤šçš„äººæˆ–æ£€æŸ¥ä½ çš„ #: src/view/com/modals/BirthDateSettings.tsx:61 msgid "This information is not shared with other users." -msgstr "æ¤ä¿¡æ¯ä¸ä¸Žå…¶ä»–用户共享。" +msgstr "æ¤ä¿¡æ¯ä¸ä¼šåˆ†äº«ç»™å…¶ä»–用户。" #: src/view/com/modals/VerifyEmail.tsx:119 msgid "This is important in case you ever need to change your email or reset your password." @@ -4147,7 +4216,7 @@ msgstr "这很é‡è¦ï¼Œä»¥é˜²ä½ å°†æ¥éœ€è¦æ›´æ”¹ç”µå邮箱或é‡ç½®å¯†ç 。 msgid "This link is taking you to the following website:" msgstr "æ¤é“¾æŽ¥å°†å¸¦ä½ 到以下网站:" -#: src/view/screens/ProfileList.tsx:834 +#: src/view/screens/ProfileList.tsx:839 msgid "This list is empty!" msgstr "æ¤åˆ—表为空ï¼" @@ -4157,7 +4226,7 @@ msgstr "该å称已被使用" #: src/view/com/post-thread/PostThreadItem.tsx:125 msgid "This post has been deleted." -msgstr "æ¤å¸–å·²è¢«åˆ é™¤ã€‚" +msgstr "æ¤å¸–åå·²è¢«åˆ é™¤ã€‚" #: src/view/com/modals/ModerationDetails.tsx:62 msgid "This user has blocked you. You cannot view their content." @@ -4179,11 +4248,11 @@ msgstr "æ¤ç”¨æˆ·åŒ…å«åœ¨ä½ å·²éšè—çš„ <0/> 列表ä¸ã€‚" msgid "This warning is only available for posts with media attached." msgstr "æ¤è¦å‘Šä»…适用于附带媒体的帖å。" -#: src/components/dialogs/MutedWords.tsx:236 +#: src/components/dialogs/MutedWords.tsx:285 msgid "This will delete {0} from your muted words. You can always add it back later." -msgstr "" +msgstr "è¿™å°†ä»Žä½ çš„éšè—è¯ä¸åˆ 除 {0}ã€‚ä½ éšæ—¶å¯ä»¥é‡æ–°æ·»åŠ ã€‚" -#: src/view/com/util/forms/PostDropdownBtn.tsx:237 +#: src/view/com/util/forms/PostDropdownBtn.tsx:282 msgid "This will hide this post from your feeds." msgstr "è¿™å°†åœ¨ä½ çš„ä¿¡æ¯æµä¸éšè—æ¤å¸–å。" @@ -4194,19 +4263,19 @@ msgstr "讨论串首选项" #: src/view/screens/PreferencesThreads.tsx:119 msgid "Threaded Mode" -msgstr "分层模å¼" +msgstr "讨论串模å¼" -#: src/Navigation.tsx:255 +#: src/Navigation.tsx:257 msgid "Threads Preferences" msgstr "讨论串首选项" -#: src/components/dialogs/MutedWords.tsx:95 +#: src/components/dialogs/MutedWords.tsx:113 msgid "Toggle between muted word options." -msgstr "" +msgstr "在éšè—è¯é€‰é¡¹ä¹‹é—´åˆ‡æ¢ã€‚" #: src/view/com/util/forms/DropdownButton.tsx:246 msgid "Toggle dropdown" -msgstr "切æ¢ä¸‹æ‹‰èœå•" +msgstr "切æ¢ä¸‹æ‹‰å¼èœå•" #: src/view/com/modals/EditImage.tsx:271 msgid "Transformations" @@ -4214,7 +4283,8 @@ msgstr "转æ¢" #: src/view/com/post-thread/PostThreadItem.tsx:685 #: src/view/com/post-thread/PostThreadItem.tsx:687 -#: src/view/com/util/forms/PostDropdownBtn.tsx:156 +#: src/view/com/util/forms/PostDropdownBtn.tsx:215 +#: src/view/com/util/forms/PostDropdownBtn.tsx:217 msgid "Translate" msgstr "翻译" @@ -4259,44 +4329,48 @@ msgstr "å–æ¶ˆå±è”½" #: src/view/com/util/post-ctrls/RepostButton.tsx:60 #: src/view/com/util/post-ctrls/RepostButton.web.tsx:48 msgid "Undo repost" -msgstr "撤销转å‘" +msgstr "å–æ¶ˆè½¬å‘" #: src/view/com/profile/FollowButton.tsx:55 msgctxt "action" msgid "Unfollow" -msgstr "å–å…³" +msgstr "å–æ¶ˆå…³æ³¨" #: src/view/com/profile/ProfileHeader.tsx:485 msgid "Unfollow {0}" -msgstr "å–å…³ {0}" +msgstr "å–æ¶ˆå…³æ³¨ {0}" #: src/view/com/auth/create/state.ts:262 msgid "Unfortunately, you do not meet the requirements to create an account." msgstr "å¾ˆé—æ†¾ï¼Œä½ ä¸ç¬¦åˆåˆ›å»ºè´¦æˆ·çš„è¦æ±‚。" #: src/view/com/util/post-ctrls/PostCtrls.tsx:182 -#: src/view/com/util/post-ctrls/PostCtrls.tsx:216 msgid "Unlike" msgstr "å–æ¶ˆå–œæ¬¢" -#: src/components/TagMenu/index.tsx:253 +#: src/components/TagMenu/index.tsx:249 #: src/view/screens/ProfileList.tsx:597 msgid "Unmute" msgstr "å–æ¶ˆéšè—" -#: src/components/TagMenu/index.web.tsx:90 +#: src/components/TagMenu/index.web.tsx:104 msgid "Unmute {truncatedTag}" -msgstr "" +msgstr "å–æ¶ˆéšè— {truncatedTag}" #: src/view/com/profile/ProfileHeader.tsx:326 msgid "Unmute Account" msgstr "å–æ¶ˆéšè—账户" +#: src/components/TagMenu/index.tsx:208 +msgid "Unmute all {displayTag} posts" +msgstr "å–æ¶ˆéšè—所有 {displayTag} 帖å" + #: src/components/TagMenu/index.tsx:210 -msgid "Unmute all {tag} posts" -msgstr "" +#~ msgid "Unmute all {tag} posts" +#~ msgstr "" -#: src/view/com/util/forms/PostDropdownBtn.tsx:202 +#: src/view/com/util/forms/PostDropdownBtn.tsx:251 +#: src/view/com/util/forms/PostDropdownBtn.tsx:256 msgid "Unmute thread" msgstr "å–æ¶ˆéšè—讨论串" @@ -4331,7 +4405,7 @@ msgstr "å°†æ–‡æœ¬æ–‡ä»¶ä¸Šä¼ è‡³ï¼š" #: src/view/screens/AppPasswords.tsx:195 msgid "Use app passwords to login to other Bluesky clients without giving full access to your account or password." -msgstr "使用应用程åºå¯†ç 登录到其他 Bluesky å®¢æˆ·ç«¯ï¼Œè€Œæ— éœ€å¯¹å…¶æŽˆäºˆä½ è´¦æˆ·æˆ–å¯†ç 的完全访问æƒé™ã€‚" +msgstr "使用应用专用密ç 登录到其他 Bluesky å®¢æˆ·ç«¯ï¼Œè€Œæ— éœ€å¯¹å…¶æŽˆäºˆä½ è´¦æˆ·æˆ–å¯†ç 的完全访问æƒé™ã€‚" #: src/view/com/modals/ChangeHandle.tsx:515 msgid "Use default provider" @@ -4380,13 +4454,13 @@ msgstr "用户识别符" msgid "User list by {0}" msgstr "{0} 的用户列表" -#: src/view/screens/ProfileList.tsx:762 +#: src/view/screens/ProfileList.tsx:763 msgid "User list by <0/>" msgstr "<0/> 的用户列表" #: src/view/com/lists/ListCard.tsx:83 #: src/view/com/modals/UserAddRemoveLists.tsx:196 -#: src/view/screens/ProfileList.tsx:760 +#: src/view/screens/ProfileList.tsx:761 msgid "User list by you" msgstr "ä½ çš„ç”¨æˆ·åˆ—è¡¨" @@ -4407,7 +4481,7 @@ msgstr "用户列表" msgid "Username or email address" msgstr "ç”¨æˆ·åæˆ–电å邮箱" -#: src/view/screens/ProfileList.tsx:796 +#: src/view/screens/ProfileList.tsx:797 msgid "Users" msgstr "用户" @@ -4446,7 +4520,7 @@ msgstr "验è¯ä½ 的邮箱" #: src/screens/Onboarding/index.tsx:42 msgid "Video Games" -msgstr "视频游æˆ" +msgstr "ç”µåæ¸¸æˆ" #: src/view/com/profile/ProfileHeader.tsx:662 msgid "View {0}'s avatar" @@ -4462,7 +4536,7 @@ msgstr "查看整个讨论串" #: src/view/com/posts/FeedErrorMessage.tsx:172 msgid "View profile" -msgstr "查看资料" +msgstr "查看个人资料" #: src/view/com/profile/ProfileSubpageHeader.tsx:128 msgid "View the avatar" @@ -4481,6 +4555,10 @@ msgstr "è¦å‘Š" msgid "We also think you'll like \"For You\" by Skygaze:" msgstr "æˆ‘ä»¬è®¤ä¸ºè¿˜ä½ ä¼šå–œæ¬¢ Skygaze 所维护的 \"For You\":" +#: src/screens/Hashtag.tsx:132 +msgid "We couldn't find any results for that hashtag." +msgstr "找ä¸åˆ°ä»»ä½•与该è¯é¢˜æ ‡ç¾ç›¸å…³çš„结果。" + #: src/screens/Deactivated.tsx:133 msgid "We estimate {estimatedTime} until your account is ready." msgstr "æˆ‘ä»¬ä¼°è®¡è¿˜éœ€è¦ {estimatedTime} æ‰èƒ½å®Œæˆä½ 的账户准备。" @@ -4493,9 +4571,9 @@ msgstr "æˆ‘ä»¬å¸Œæœ›ä½ åœ¨æ¤åº¦è¿‡æ„‰å¿«çš„æ—¶å…‰ã€‚请记ä½ï¼ŒBluesky 是:" msgid "We ran out of posts from your follows. Here's the latest from <0/>." msgstr "我们已ç»çœ‹å®Œäº†ä½ 关注的帖å。这是æ¥è‡ª <0/> 的最新消æ¯ã€‚" -#: src/components/dialogs/MutedWords.tsx:161 +#: src/components/dialogs/MutedWords.tsx:204 msgid "We recommend avoiding common words that appear in many posts, since it can result in no posts being shown." -msgstr "" +msgstr "ä¸å»ºè®®æ‚¨ä½¿ç”¨ä¼šå‡ºçŽ°åœ¨è®¸å¤šå¸–åä¸çš„常è§è¯æ±‡ï¼Œè¿™å¯èƒ½å¯¼è‡´ä½ 的时间线上没有帖å坿˜¾ç¤ºã€‚" #: src/screens/Onboarding/StepAlgoFeeds/index.tsx:124 msgid "We recommend our \"Discover\" feed:" @@ -4525,14 +4603,15 @@ msgstr "我们éžå¸¸é«˜å…´ä½ åŠ å…¥æˆ‘ä»¬ï¼" msgid "We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @{handleOrDid}." msgstr "很抱æ‰ï¼Œæˆ‘ä»¬æ— æ³•è§£æžæ¤åˆ—表。如果问题æŒç»å‘生,请è”系列表创建者,@{handleOrDid}。" -#: src/components/dialogs/MutedWords.tsx:182 +#: src/components/dialogs/MutedWords.tsx:230 msgid "We're sorry, but we weren't able to load your muted words at this time. Please try again." -msgstr "" +msgstr "很抱æ‰ï¼Œæˆ‘ä»¬æ— æ³•åŠ è½½ä½ çš„éšè—è¯åˆ—表。请é‡è¯•。" #: src/view/screens/Search/Search.tsx:254 msgid "We're sorry, but your search could not be completed. Please try again in a few minutes." msgstr "很抱æ‰ï¼Œæ— 法完æˆä½ çš„æœç´¢ã€‚请ç¨åŽå†è¯•。" +#: src/components/Lists.tsx:211 #: src/view/screens/NotFound.tsx:48 msgid "We're sorry! We can't find the page you were looking for." msgstr "很抱æ‰ï¼æˆ‘们找ä¸åˆ°ä½ æ£åœ¨å¯»æ‰¾çš„页é¢ã€‚" @@ -4634,7 +4713,7 @@ msgstr "ä½ ç›®å‰è¿˜æ²¡æœ‰ä»»ä½•ä¿å˜çš„ä¿¡æ¯æµã€‚" #: src/view/com/post-thread/PostThread.tsx:465 msgid "You have blocked the author or you have been blocked by the author." -msgstr "ä½ å·²å±è”½è¯¥ä½œè€…ï¼Œæˆ–ä½ å·²è¢«è¯¥ä½œè€…å±è”½ã€‚" +msgstr "ä½ å·²å±è”½è¯¥å¸–åä½œè€…ï¼Œæˆ–ä½ å·²è¢«è¯¥ä½œè€…å±è”½ã€‚" #: src/view/com/modals/ModerationDetails.tsx:56 msgid "You have blocked this user. You cannot view their content." @@ -4645,7 +4724,7 @@ msgstr "ä½ å·²å±è”½äº†æ¤ç”¨æˆ·ï¼Œä½ å°†æ— æ³•æŸ¥çœ‹ä»–ä»¬å‘布的内容。" #: src/view/com/modals/ChangePassword.tsx:87 #: src/view/com/modals/ChangePassword.tsx:121 msgid "You have entered an invalid code. It should look like XXXXX-XXXXX." -msgstr "ä½ è¾“å…¥çš„é‚€è¯·ç æ— 效。它应该长得åƒè¿™æ · XXXXX-XXXXX。" +msgstr "ä½ è¾“å…¥çš„ç¡®è®¤ç æ— 效。它应该长得åƒè¿™æ · XXXXX-XXXXX。" #: src/view/com/modals/ModerationDetails.tsx:87 msgid "You have muted this user." @@ -4666,15 +4745,15 @@ msgstr "ä½ è¿˜æ²¡æœ‰å±è”½ä»»ä½•è´¦å·ã€‚è¦å±è”½è´¦å·ï¼Œè¯·è½¬åˆ°å…¶ä¸ªäººèµ„ #: src/view/screens/AppPasswords.tsx:87 msgid "You have not created any app passwords yet. You can create one by pressing the button below." -msgstr "ä½ å°šæœªåˆ›å»ºä»»ä½• App 专用密ç ,å¯ä»¥é€šè¿‡ç‚¹å‡»ä¸‹é¢çš„æŒ‰é’®æ¥åˆ›å»ºä¸€ä¸ªã€‚" +msgstr "ä½ å°šæœªåˆ›å»ºä»»ä½•åº”ç”¨ä¸“ç”¨å¯†ç ,å¯ä»¥é€šè¿‡ç‚¹å‡»ä¸‹é¢çš„æŒ‰é’®æ¥åˆ›å»ºä¸€ä¸ªã€‚" #: src/view/screens/ModerationMutedAccounts.tsx:131 msgid "You have not muted any accounts yet. To mute an account, go to their profile and selected \"Mute account\" from the menu on their account." msgstr "ä½ è¿˜æ²¡æœ‰éšè—任何账å·ã€‚è¦éšè—è´¦å·ï¼Œè¯·è½¬åˆ°å…¶ä¸ªäººèµ„料并在其账å·ä¸Šçš„èœå•ä¸é€‰æ‹© \"éšè—è´¦å·\"。" -#: src/components/dialogs/MutedWords.tsx:202 +#: src/components/dialogs/MutedWords.tsx:250 msgid "You haven't muted any words or tags yet" -msgstr "" +msgstr "ä½ è¿˜æ²¡æœ‰éšè—ä»»ä½•è¯æˆ–è¯é¢˜æ ‡ç¾" #: src/view/com/modals/ContentFilteringSettings.tsx:175 msgid "You must be 18 or older to enable adult content." @@ -4684,17 +4763,17 @@ msgstr "ä½ å¿…é¡»å¹´æ»¡18å²åŠä»¥ä¸Šæ‰èƒ½å¯ç”¨æˆäººå†…容。" msgid "You must be 18 years or older to enable adult content" msgstr "ä½ å¿…é¡»å¹´æ»¡18å²åŠä»¥ä¸Šæ‰èƒ½å¯ç”¨æˆäººå†…容" -#: src/view/com/util/forms/PostDropdownBtn.tsx:129 +#: src/view/com/util/forms/PostDropdownBtn.tsx:147 msgid "You will no longer receive notifications for this thread" msgstr "ä½ å°†ä¸å†æ”¶åˆ°è¿™æ¡è®¨è®ºä¸²çš„通知" -#: src/view/com/util/forms/PostDropdownBtn.tsx:132 +#: src/view/com/util/forms/PostDropdownBtn.tsx:150 msgid "You will now receive notifications for this thread" msgstr "ä½ å°†æ”¶åˆ°è¿™æ¡è®¨è®ºä¸²çš„通知" #: src/view/com/auth/login/SetNewPasswordForm.tsx:107 msgid "You will receive an email with a \"reset code.\" Enter that code here, then enter your new password." -msgstr "ä½ å°†æ”¶åˆ°ä¸€å°å¸¦æœ‰é‡ç½®ä»£ç 的电å邮件。请在æ¤è¾“入该é‡ç½®ä»£ç ,然åŽè¾“å…¥ä½ çš„æ–°å¯†ç 。" +msgstr "ä½ å°†æ”¶åˆ°ä¸€å°å¸¦æœ‰ç¡®è®¤ç 的电å邮件。请在æ¤è¾“入该确认ç ,然åŽè¾“å…¥ä½ çš„æ–°å¯†ç 。" #: src/screens/Onboarding/StepModeration/index.tsx:72 msgid "You're in control" @@ -4714,7 +4793,7 @@ msgstr "ä½ å·²è®¾ç½®å®Œæˆï¼" msgid "You've reached the end of your feed! Find some more accounts to follow." msgstr "ä½ å·²ç»æµè§ˆå®Œä½ çš„è®¢é˜…ä¿¡æ¯æµå•¦ï¼å¯»æ‰¾ä¸€äº›æ›´å¤šçš„è´¦å·å…³æ³¨å§ã€‚" -#: src/view/com/auth/create/Step1.tsx:74 +#: src/view/com/auth/create/Step1.tsx:67 msgid "Your account" msgstr "ä½ çš„è´¦æˆ·" @@ -4724,9 +4803,9 @@ msgstr "ä½ çš„è´¦æˆ·å·²åˆ é™¤" #: src/view/screens/Settings/ExportCarDialog.tsx:47 msgid "Your account repository, containing all public data records, can be downloaded as a \"CAR\" file. This file does not include media embeds, such as images, or your private data, which must be fetched separately." -msgstr "" +msgstr "æ‚¨çš„å¸æˆ·æ•°æ®åº“åŒ…å«æ‰€æœ‰å…¬å…±æ•°æ®è®°å½•,它们将被导出为“CARâ€æ–‡ä»¶ã€‚æ¤æ–‡ä»¶ä¸åŒ…括帖åä¸çš„åª’ä½“ï¼Œä¾‹å¦‚å›¾åƒæˆ–您的éšç§æ•°æ®ï¼Œè¿™äº›æ•°æ®éœ€è¦å¦å¤–获å–。" -#: src/view/com/auth/create/Step1.tsx:238 +#: src/view/com/auth/create/Step1.tsx:215 msgid "Your birth date" msgstr "ä½ çš„ç”Ÿæ—¥" @@ -4745,8 +4824,8 @@ msgid "Your email appears to be invalid." msgstr "ä½ çš„ç”µåé‚®ç®±ä¼¼ä¹Žæ— æ•ˆã€‚" #: src/view/com/modals/Waitlist.tsx:109 -msgid "Your email has been saved! We'll be in touch soon." -msgstr "ä½ çš„ç”µå邮箱已ä¿å˜ï¼æˆ‘们将很快è”ç³»ä½ ã€‚" +#~ msgid "Your email has been saved! We'll be in touch soon." +#~ msgstr "ä½ çš„ç”µå邮箱已ä¿å˜ï¼æˆ‘们将很快è”ç³»ä½ ã€‚" #: src/view/com/modals/ChangeEmail.tsx:125 msgid "Your email has been updated but not verified. As a next step, please verify your new email." @@ -4758,7 +4837,7 @@ msgstr "ä½ çš„ç”µå邮箱尚未验è¯ã€‚这是一个é‡è¦çš„安全æ¥éª¤ï¼Œæˆ‘ #: src/view/com/posts/FollowingEmptyState.tsx:47 msgid "Your following feed is empty! Follow more users to see what's happening." -msgstr "ä½ çš„å…³æ³¨ä¿¡æ¯æµä¸ºç©ºï¼å…³æ³¨æ›´å¤šç”¨æˆ·åŽ»çœ‹çœ‹ä»–ä»¬å‘了什么什么。" +msgstr "ä½ çš„å…³æ³¨ä¿¡æ¯æµä¸ºç©ºï¼å…³æ³¨æ›´å¤šç”¨æˆ·åŽ»çœ‹çœ‹ä»–ä»¬å‘了什么。" #: src/view/com/auth/create/Step2.tsx:83 msgid "Your full handle will be" @@ -4772,25 +4851,25 @@ msgstr "ä½ çš„å®Œæ•´ç”¨æˆ·è¯†åˆ«ç¬¦å°†ä¿®æ”¹ä¸º <0>@{0}</0>" #: src/view/shell/desktop/RightNav.tsx:137 #: src/view/shell/Drawer.tsx:660 #~ msgid "Your invite codes are hidden when logged in using an App Password" -#~ msgstr "在使用 App 专用密ç ç™»å½•æ—¶ï¼Œä½ çš„é‚€è¯·ç 将被éšè—" +#~ msgstr "在使用应用专用密ç ç™»å½•æ—¶ï¼Œä½ çš„é‚€è¯·ç 将被éšè—" -#: src/components/dialogs/MutedWords.tsx:173 +#: src/components/dialogs/MutedWords.tsx:221 msgid "Your muted words" -msgstr "" +msgstr "ä½ çš„éšè—è¯" #: src/view/com/modals/ChangePassword.tsx:155 msgid "Your password has been changed successfully!" -msgstr "ä½ çš„å¯†ç 已更改æˆåŠŸï¼" +msgstr "ä½ çš„å¯†ç å·²æˆåŠŸæ›´æ”¹ï¼" #: src/view/com/composer/Composer.tsx:274 msgid "Your post has been published" -msgstr "ä½ çš„å¸–åå·²å‘é€" +msgstr "ä½ çš„å¸–åå·²å‘布" #: src/screens/Onboarding/StepFinished.tsx:105 #: src/view/com/auth/onboarding/WelcomeDesktop.tsx:59 #: src/view/com/auth/onboarding/WelcomeMobile.tsx:59 msgid "Your posts, likes, and blocks are public. Mutes are private." -msgstr "ä½ çš„å¸–åã€ç‚¹èµžå’Œå±è”½æ˜¯å…¬å¼€å¯è§çš„,而éšè—ä¸å¯è§ã€‚" +msgstr "ä½ çš„å¸–åã€å–œæ¬¢å’Œå±è”½æ˜¯å…¬å¼€å¯è§çš„,而éšè—ä¸å¯è§ã€‚" #: src/view/com/modals/SwitchAccount.tsx:84 #: src/view/screens/Settings/index.tsx:118 @@ -4799,7 +4878,7 @@ msgstr "ä½ çš„ä¸ªäººèµ„æ–™" #: src/view/com/composer/Composer.tsx:273 msgid "Your reply has been published" -msgstr "ä½ çš„å›žå¤å·²å‘é€" +msgstr "ä½ çš„å›žå¤å·²å‘布" #: src/view/com/auth/create/Step2.tsx:65 msgid "Your user handle" diff --git a/src/routes.ts b/src/routes.ts index 5c263fd6f..f6f372947 100644 --- a/src/routes.ts +++ b/src/routes.ts @@ -21,7 +21,9 @@ export const router = new Router({ PostRepostedBy: '/profile/:name/post/:rkey/reposted-by', ProfileFeed: '/profile/:name/feed/:rkey', ProfileFeedLikedBy: '/profile/:name/feed/:rkey/liked-by', + ProfileLabelerLikedBy: '/profile/:name/labeler/liked-by', Debug: '/sys/debug', + DebugMod: '/sys/debug-mod', Log: '/sys/log', AppPasswords: '/settings/app-passwords', PreferencesFollowingFeed: '/settings/following-feed', diff --git a/src/screens/Hashtag.tsx b/src/screens/Hashtag.tsx index 776cc585e..46452f087 100644 --- a/src/screens/Hashtag.tsx +++ b/src/screens/Hashtag.tsx @@ -128,8 +128,8 @@ export default function HashtagScreen({ isError={isError} isEmpty={posts.length < 1} onRetry={refetch} - notFoundType="results" - empty={_(msg`We couldn't find any results for that hashtag.`)} + emptyTitle="results" + emptyMessage={_(msg`We couldn't find any results for that hashtag.`)} /> {!isLoading && posts.length > 0 && ( <List<PostView> diff --git a/src/screens/Moderation/index.tsx b/src/screens/Moderation/index.tsx new file mode 100644 index 000000000..d73823fad --- /dev/null +++ b/src/screens/Moderation/index.tsx @@ -0,0 +1,556 @@ +import React from 'react' +import {View} from 'react-native' +import {useFocusEffect} from '@react-navigation/native' +import {ComAtprotoLabelDefs} from '@atproto/api' +import {Trans, msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {LABELS} from '@atproto/api' +import {useSafeAreaFrame} from 'react-native-safe-area-context' + +import {NativeStackScreenProps, CommonNavigatorParams} from '#/lib/routes/types' +import {CenteredView} from '#/view/com/util/Views' +import {ViewHeader} from '#/view/com/util/ViewHeader' +import {useAnalytics} from 'lib/analytics/analytics' +import {useSetMinimalShellMode} from '#/state/shell' +import {useSession} from '#/state/session' +import { + useProfileQuery, + useProfileUpdateMutation, +} from '#/state/queries/profile' +import {ScrollView} from '#/view/com/util/Views' + +import { + UsePreferencesQueryResponse, + useMyLabelersQuery, + usePreferencesQuery, + usePreferencesSetAdultContentMutation, +} from '#/state/queries/preferences' + +import {getLabelingServiceTitle} from '#/lib/moderation' +import {logger} from '#/logger' +import {useTheme, atoms as a, useBreakpoints, ViewStyleProp} from '#/alf' +import {Divider} from '#/components/Divider' +import {CircleBanSign_Stroke2_Corner0_Rounded as CircleBanSign} from '#/components/icons/CircleBanSign' +import {Group3_Stroke2_Corner0_Rounded as Group} from '#/components/icons/Group' +import {Person_Stroke2_Corner0_Rounded as Person} from '#/components/icons/Person' +import {ChevronRight_Stroke2_Corner0_Rounded as ChevronRight} from '#/components/icons/Chevron' +import {Filter_Stroke2_Corner0_Rounded as Filter} from '#/components/icons/Filter' +import {Text} from '#/components/Typography' +import * as Toggle from '#/components/forms/Toggle' +import {InlineLink, Link} from '#/components/Link' +import {Button, ButtonText} from '#/components/Button' +import {Loader} from '#/components/Loader' +import * as LabelingService from '#/components/LabelingServiceCard' +import {GlobalModerationLabelPref} from '#/components/moderation/GlobalModerationLabelPref' +import {useGlobalDialogsControlContext} from '#/components/dialogs/Context' +import {Props as SVGIconProps} from '#/components/icons/common' +import {BirthDateSettingsDialog} from '#/components/dialogs/BirthDateSettings' +import * as Dialog from '#/components/Dialog' + +function ErrorState({error}: {error: string}) { + const t = useTheme() + return ( + <View style={[a.p_xl]}> + <Text + style={[ + a.text_md, + a.leading_normal, + a.pb_md, + t.atoms.text_contrast_medium, + ]}> + <Trans> + Hmmmm, it seems we're having trouble loading this data. See below for + more details. If this issue persists, please contact us. + </Trans> + </Text> + <View + style={[ + a.relative, + a.py_md, + a.px_lg, + a.rounded_md, + a.mb_2xl, + t.atoms.bg_contrast_25, + ]}> + <Text style={[a.text_md, a.leading_normal]}>{error}</Text> + </View> + </View> + ) +} + +export function ModerationScreen( + _props: NativeStackScreenProps<CommonNavigatorParams, 'Moderation'>, +) { + const t = useTheme() + const {_} = useLingui() + const { + isLoading: isPreferencesLoading, + error: preferencesError, + data: preferences, + } = usePreferencesQuery() + const {gtMobile} = useBreakpoints() + const {height} = useSafeAreaFrame() + + const isLoading = isPreferencesLoading + const error = preferencesError + + return ( + <CenteredView + testID="moderationScreen" + style={[ + t.atoms.border_contrast_low, + t.atoms.bg, + {minHeight: height}, + ...(gtMobile ? [a.border_l, a.border_r] : []), + ]}> + <ViewHeader title={_(msg`Moderation`)} showOnDesktop /> + + {isLoading ? ( + <View style={[a.w_full, a.align_center, a.pt_2xl]}> + <Loader size="xl" fill={t.atoms.text.color} /> + </View> + ) : error || !preferences ? ( + <ErrorState + error={ + preferencesError?.toString() || + _(msg`Something went wrong, please try again.`) + } + /> + ) : ( + <ModerationScreenInner preferences={preferences} /> + )} + </CenteredView> + ) +} + +function SubItem({ + title, + icon: Icon, + style, +}: ViewStyleProp & { + title: string + icon: React.ComponentType<SVGIconProps> +}) { + const t = useTheme() + return ( + <View + style={[ + a.w_full, + a.flex_row, + a.align_center, + a.justify_between, + a.p_lg, + a.gap_sm, + style, + ]}> + <View style={[a.flex_row, a.align_center, a.gap_md]}> + <Icon size="md" style={[t.atoms.text_contrast_medium]} /> + <Text style={[a.text_sm, a.font_bold]}>{title}</Text> + </View> + <ChevronRight + size="sm" + style={[t.atoms.text_contrast_low, a.self_end, {paddingBottom: 2}]} + /> + </View> + ) +} + +export function ModerationScreenInner({ + preferences, +}: { + preferences: UsePreferencesQueryResponse +}) { + const {_} = useLingui() + const t = useTheme() + const setMinimalShellMode = useSetMinimalShellMode() + const {screen} = useAnalytics() + const {gtMobile} = useBreakpoints() + const {mutedWordsDialogControl} = useGlobalDialogsControlContext() + const birthdateDialogControl = Dialog.useDialogControl() + const { + isLoading: isLabelersLoading, + data: labelers, + error: labelersError, + } = useMyLabelersQuery() + + useFocusEffect( + React.useCallback(() => { + screen('Moderation') + setMinimalShellMode(false) + }, [screen, setMinimalShellMode]), + ) + + const {mutateAsync: setAdultContentPref, variables: optimisticAdultContent} = + usePreferencesSetAdultContentMutation() + const adultContentEnabled = !!( + (optimisticAdultContent && optimisticAdultContent.enabled) || + (!optimisticAdultContent && preferences.moderationPrefs.adultContentEnabled) + ) + const ageNotSet = !preferences.userAge + const isUnderage = (preferences.userAge || 0) < 18 + + const onToggleAdultContentEnabled = React.useCallback( + async (selected: boolean) => { + try { + await setAdultContentPref({ + enabled: selected, + }) + } catch (e: any) { + logger.error(`Failed to set adult content pref`, { + message: e.message, + }) + } + }, + [setAdultContentPref], + ) + + return ( + <ScrollView + contentContainerStyle={[ + a.border_0, + a.pt_2xl, + a.px_lg, + gtMobile && a.px_2xl, + ]}> + <Text + style={[a.text_md, a.font_bold, a.pb_md, t.atoms.text_contrast_high]}> + <Trans>Moderation tools</Trans> + </Text> + + <View + style={[ + a.w_full, + a.rounded_md, + a.overflow_hidden, + t.atoms.bg_contrast_25, + ]}> + <Button + testID="mutedWordsBtn" + label={_(msg`Open muted words and tags settings`)} + onPress={() => mutedWordsDialogControl.open()}> + {state => ( + <SubItem + title={_(msg`Muted words & tags`)} + icon={Filter} + style={[ + (state.hovered || state.pressed) && [t.atoms.bg_contrast_50], + ]} + /> + )} + </Button> + <Divider /> + <Link testID="moderationlistsBtn" to="/moderation/modlists"> + {state => ( + <SubItem + title={_(msg`Moderation lists`)} + icon={Group} + style={[ + (state.hovered || state.pressed) && [t.atoms.bg_contrast_50], + ]} + /> + )} + </Link> + <Divider /> + <Link testID="mutedAccountsBtn" to="/moderation/muted-accounts"> + {state => ( + <SubItem + title={_(msg`Muted accounts`)} + icon={Person} + style={[ + (state.hovered || state.pressed) && [t.atoms.bg_contrast_50], + ]} + /> + )} + </Link> + <Divider /> + <Link testID="blockedAccountsBtn" to="/moderation/blocked-accounts"> + {state => ( + <SubItem + title={_(msg`Blocked accounts`)} + icon={CircleBanSign} + style={[ + (state.hovered || state.pressed) && [t.atoms.bg_contrast_50], + ]} + /> + )} + </Link> + </View> + + <Text + style={[ + a.pt_2xl, + a.pb_md, + a.text_md, + a.font_bold, + t.atoms.text_contrast_high, + ]}> + <Trans>Content filters</Trans> + </Text> + + <View style={[a.gap_md]}> + {ageNotSet && ( + <> + <Button + label={_(msg`Confirm your birthdate`)} + size="small" + variant="solid" + color="secondary" + onPress={() => { + birthdateDialogControl.open() + }} + style={[a.justify_between, a.rounded_md, a.px_lg, a.py_lg]}> + <ButtonText> + <Trans>Confirm your age:</Trans> + </ButtonText> + <ButtonText> + <Trans>Set birthdate</Trans> + </ButtonText> + </Button> + + <BirthDateSettingsDialog control={birthdateDialogControl} /> + </> + )} + <View + style={[ + a.w_full, + a.rounded_md, + a.overflow_hidden, + t.atoms.bg_contrast_25, + ]}> + {!ageNotSet && !isUnderage && ( + <> + <View + style={[ + a.py_lg, + a.px_lg, + a.flex_row, + a.align_center, + a.justify_between, + ]}> + <Text style={[a.font_semibold, t.atoms.text_contrast_high]}> + <Trans>Enable adult content</Trans> + </Text> + <Toggle.Item + label={_(msg`Toggle to enable or disable adult content`)} + name="adultContent" + value={adultContentEnabled} + onChange={onToggleAdultContentEnabled}> + <View style={[a.flex_row, a.align_center, a.gap_sm]}> + <Text style={[t.atoms.text_contrast_medium]}> + {adultContentEnabled ? ( + <Trans>Enabled</Trans> + ) : ( + <Trans>Disabled</Trans> + )} + </Text> + <Toggle.Switch /> + </View> + </Toggle.Item> + </View> + <Divider /> + </> + )} + {!isUnderage && adultContentEnabled && ( + <> + <GlobalModerationLabelPref labelValueDefinition={LABELS.porn} /> + <Divider /> + <GlobalModerationLabelPref labelValueDefinition={LABELS.sexual} /> + <Divider /> + <GlobalModerationLabelPref + labelValueDefinition={LABELS['graphic-media']} + /> + <Divider /> + </> + )} + <GlobalModerationLabelPref labelValueDefinition={LABELS.nudity} /> + </View> + </View> + + <Text + style={[ + a.text_md, + a.font_bold, + a.pt_2xl, + a.pb_md, + t.atoms.text_contrast_high, + ]}> + <Trans>Advanced</Trans> + </Text> + + {isLabelersLoading ? ( + <View style={[a.w_full, a.align_center, a.p_lg]}> + <Loader size="xl" /> + </View> + ) : labelersError || !labelers ? ( + <View style={[a.p_lg, a.rounded_sm, t.atoms.bg_contrast_25]}> + <Text> + <Trans> + We were unable to load your configured labelers at this time. + </Trans> + </Text> + </View> + ) : ( + <View style={[a.rounded_sm, t.atoms.bg_contrast_25]}> + {labelers.map((labeler, i) => { + return ( + <React.Fragment key={labeler.creator.did}> + {i !== 0 && <Divider />} + <LabelingService.Link labeler={labeler}> + {state => ( + <LabelingService.Outer + style={[ + i === 0 && { + borderTopLeftRadius: a.rounded_sm.borderRadius, + borderTopRightRadius: a.rounded_sm.borderRadius, + }, + i === labelers.length - 1 && { + borderBottomLeftRadius: a.rounded_sm.borderRadius, + borderBottomRightRadius: a.rounded_sm.borderRadius, + }, + (state.hovered || state.pressed) && [ + t.atoms.bg_contrast_50, + ], + ]}> + <LabelingService.Avatar avatar={labeler.creator.avatar} /> + <LabelingService.Content> + <LabelingService.Title + value={getLabelingServiceTitle({ + displayName: labeler.creator.displayName, + handle: labeler.creator.handle, + })} + /> + <LabelingService.Description + value={labeler.creator.description} + handle={labeler.creator.handle} + /> + </LabelingService.Content> + </LabelingService.Outer> + )} + </LabelingService.Link> + </React.Fragment> + ) + })} + </View> + )} + + <Text + style={[ + a.text_md, + a.font_bold, + a.pt_2xl, + a.pb_md, + t.atoms.text_contrast_high, + ]}> + <Trans>Logged-out visibility</Trans> + </Text> + + <PwiOptOut /> + + <View style={{height: 200}} /> + </ScrollView> + ) +} + +function PwiOptOut() { + const t = useTheme() + const {_} = useLingui() + const {currentAccount} = useSession() + const {data: profile} = useProfileQuery({did: currentAccount?.did}) + const updateProfile = useProfileUpdateMutation() + + const isOptedOut = + profile?.labels?.some(l => l.val === '!no-unauthenticated') || false + const canToggle = profile && !updateProfile.isPending + + const onToggleOptOut = React.useCallback(() => { + if (!profile) { + return + } + let wasAdded = false + updateProfile.mutate({ + profile, + updates: existing => { + // create labels attr if needed + existing.labels = ComAtprotoLabelDefs.isSelfLabels(existing.labels) + ? existing.labels + : { + $type: 'com.atproto.label.defs#selfLabels', + values: [], + } + + // toggle the label + const hasLabel = existing.labels.values.some( + l => l.val === '!no-unauthenticated', + ) + if (hasLabel) { + wasAdded = false + existing.labels.values = existing.labels.values.filter( + l => l.val !== '!no-unauthenticated', + ) + } else { + wasAdded = true + existing.labels.values.push({val: '!no-unauthenticated'}) + } + + // delete if no longer needed + if (existing.labels.values.length === 0) { + delete existing.labels + } + return existing + }, + checkCommitted: res => { + const exists = !!res.data.labels?.some( + l => l.val === '!no-unauthenticated', + ) + return exists === wasAdded + }, + }) + }, [updateProfile, profile]) + + return ( + <View style={[a.pt_sm]}> + <View style={[a.flex_row, a.align_center, a.justify_between, a.gap_lg]}> + <Toggle.Item + disabled={!canToggle} + value={isOptedOut} + onChange={onToggleOptOut} + name="logged_out_visibility" + style={a.flex_1} + label={_( + msg`Discourage apps from showing my account to logged-out users`, + )}> + <Toggle.Switch /> + <Toggle.Label style={[a.text_md, a.flex_1]}> + <Trans> + Discourage apps from showing my account to logged-out users + </Trans> + </Toggle.Label> + </Toggle.Item> + + {updateProfile.isPending && <Loader />} + </View> + + <View style={[a.pt_md, a.gap_md, {paddingLeft: 38}]}> + <Text style={[a.leading_snug, t.atoms.text_contrast_high]}> + <Trans> + Bluesky will not show your profile and posts to logged-out users. + Other apps may not honor this request. This does not make your + account private. + </Trans> + </Text> + <Text style={[a.font_bold, a.leading_snug, t.atoms.text_contrast_high]}> + <Trans> + Note: Bluesky is an open and public network. This setting only + limits the visibility of your content on the Bluesky app and + website, and other apps may not respect this setting. Your content + may still be shown to logged-out users by other apps and websites. + </Trans> + </Text> + + <InlineLink to="https://blueskyweb.zendesk.com/hc/en-us/articles/15835264007693-Data-Privacy"> + <Trans>Learn more about what is public on Bluesky.</Trans> + </InlineLink> + </View> + </View> + ) +} diff --git a/src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx b/src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx index dec53d2ed..1123f2675 100644 --- a/src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx +++ b/src/screens/Onboarding/StepAlgoFeeds/FeedCard.tsx @@ -238,13 +238,14 @@ function FeedCardInner({feed}: {feed: FeedSourceInfo; config: FeedConfig}) { /> </View> - <View style={[a.pt_2xs, a.flex_grow]}> + <View style={[a.pt_2xs, a.flex_1, a.flex_grow]}> <Text style={[ a.text_md, a.font_bold, ctx.selected && styles.textSelected, - ]}> + ]} + numberOfLines={1}> {feed.displayName} </Text> <Text diff --git a/src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx b/src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx index 360025c02..aaacaea0a 100644 --- a/src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx +++ b/src/screens/Onboarding/StepModeration/AdultContentEnabledPref.tsx @@ -56,7 +56,9 @@ export function AdultContentEnabledPref({ try { mutate({ - enabled: !(variables?.enabled ?? preferences?.adultContentEnabled), + enabled: !( + variables?.enabled ?? preferences?.moderationPrefs.adultContentEnabled + ), }) } catch (e) { Toast.show( @@ -75,7 +77,10 @@ export function AdultContentEnabledPref({ <Toggle.Item name={_(msg`Enable adult content in your feeds`)} label={_(msg`Enable adult content in your feeds`)} - value={variables?.enabled ?? preferences?.adultContentEnabled} + value={ + variables?.enabled ?? + preferences?.moderationPrefs.adultContentEnabled + } onChange={onToggleAdultContent}> <View style={[ @@ -85,7 +90,9 @@ export function AdultContentEnabledPref({ a.align_center, a.py_md, ]}> - <Text style={[a.font_bold]}>Enable Adult Content</Text> + <Text style={[a.font_bold]}> + <Trans>Enable Adult Content</Trans> + </Text> <Toggle.Switch /> </View> </Toggle.Item> @@ -106,7 +113,9 @@ export function AdultContentEnabledPref({ )} <Prompt.Outer control={prompt}> - <Prompt.Title>Adult Content</Prompt.Title> + <Prompt.Title> + <Trans>Adult Content</Trans> + </Prompt.Title> <Prompt.Description> <Trans> Due to Apple policies, adult content can only be enabled on the web @@ -114,7 +123,9 @@ export function AdultContentEnabledPref({ </Trans> </Prompt.Description> <Prompt.Actions> - <Prompt.Action onPress={() => prompt.close()}>OK</Prompt.Action> + <Prompt.Action onPress={() => prompt.close()}> + <Trans>OK</Trans> + </Prompt.Action> </Prompt.Actions> </Prompt.Outer> </> diff --git a/src/screens/Onboarding/StepModeration/ModerationOption.tsx b/src/screens/Onboarding/StepModeration/ModerationOption.tsx index c61b520ba..ac02a874c 100644 --- a/src/screens/Onboarding/StepModeration/ModerationOption.tsx +++ b/src/screens/Onboarding/StepModeration/ModerationOption.tsx @@ -1,40 +1,51 @@ import React from 'react' import {View} from 'react-native' -import {LabelPreference} from '@atproto/api' +import {LabelPreference, InterpretedLabelValueDefinition} from '@atproto/api' import {useLingui} from '@lingui/react' -import {msg} from '@lingui/macro' -import Animated, {Easing, Layout, FadeIn} from 'react-native-reanimated' +import {msg, Trans} from '@lingui/macro' import { - CONFIGURABLE_LABEL_GROUPS, - ConfigurableLabelGroup, usePreferencesQuery, usePreferencesSetContentLabelMutation, } from '#/state/queries/preferences' import {atoms as a, useTheme} from '#/alf' import {Text} from '#/components/Typography' import * as ToggleButton from '#/components/forms/ToggleButton' +import {useGlobalLabelStrings} from '#/lib/moderation/useGlobalLabelStrings' export function ModerationOption({ - labelGroup, - isMounted, + labelValueDefinition, + disabled, }: { - labelGroup: ConfigurableLabelGroup - isMounted: React.MutableRefObject<boolean> + labelValueDefinition: InterpretedLabelValueDefinition + disabled?: boolean }) { const {_} = useLingui() const t = useTheme() - const groupInfo = CONFIGURABLE_LABEL_GROUPS[labelGroup] const {data: preferences} = usePreferencesQuery() const {mutate, variables} = usePreferencesSetContentLabelMutation() + const label = labelValueDefinition.identifier const visibility = - variables?.visibility ?? preferences?.contentLabels?.[labelGroup] + variables?.visibility ?? preferences?.moderationPrefs.labels?.[label] + + const allLabelStrings = useGlobalLabelStrings() + const labelStrings = + labelValueDefinition.identifier in allLabelStrings + ? allLabelStrings[labelValueDefinition.identifier] + : { + name: labelValueDefinition.identifier, + description: `Labeled "${labelValueDefinition.identifier}"`, + } const onChange = React.useCallback( (vis: string[]) => { - mutate({labelGroup, visibility: vis[0] as LabelPreference}) + mutate({ + label, + visibility: vis[0] as LabelPreference, + labelerDid: undefined, + }) }, - [mutate, labelGroup], + [mutate, label], ) const labels = { @@ -44,7 +55,7 @@ export function ModerationOption({ } return ( - <Animated.View + <View style={[ a.flex_row, a.justify_between, @@ -52,33 +63,37 @@ export function ModerationOption({ a.py_xs, a.px_xs, a.align_center, - ]} - layout={Layout.easing(Easing.ease).duration(200)} - entering={isMounted.current ? FadeIn : undefined}> - <View style={[a.gap_xs, {width: '50%'}]}> - <Text style={[a.font_bold]}>{groupInfo.title}</Text> + ]}> + <View style={[a.gap_xs, a.flex_1]}> + <Text style={[a.font_bold]}>{labelStrings.name}</Text> <Text style={[t.atoms.text_contrast_medium, a.leading_snug]}> - {groupInfo.subtitle} + {labelStrings.description} </Text> </View> - <View style={[a.justify_center, {minHeight: 35}]}> - <ToggleButton.Group - label={_( - msg`Configure content filtering setting for category: ${groupInfo.title.toLowerCase()}`, - )} - values={[visibility ?? 'hide']} - onChange={onChange}> - <ToggleButton.Button name="hide" label={labels.hide}> - {labels.hide} - </ToggleButton.Button> - <ToggleButton.Button name="warn" label={labels.warn}> - {labels.warn} - </ToggleButton.Button> - <ToggleButton.Button name="ignore" label={labels.show}> - {labels.show} - </ToggleButton.Button> - </ToggleButton.Group> + <View style={[a.justify_center, {minHeight: 40}]}> + {disabled ? ( + <Text style={[a.font_bold]}> + <Trans>Hide</Trans> + </Text> + ) : ( + <ToggleButton.Group + label={_( + msg`Configure content filtering setting for category: ${labelStrings.name.toLowerCase()}`, + )} + values={[visibility ?? 'hide']} + onChange={onChange}> + <ToggleButton.Button name="ignore" label={labels.show}> + {labels.show} + </ToggleButton.Button> + <ToggleButton.Button name="warn" label={labels.warn}> + {labels.warn} + </ToggleButton.Button> + <ToggleButton.Button name="hide" label={labels.hide}> + {labels.hide} + </ToggleButton.Button> + </ToggleButton.Group> + )} </View> - </Animated.View> + </View> ) } diff --git a/src/screens/Onboarding/StepModeration/index.tsx b/src/screens/Onboarding/StepModeration/index.tsx index 543a5b159..9b52f9f43 100644 --- a/src/screens/Onboarding/StepModeration/index.tsx +++ b/src/screens/Onboarding/StepModeration/index.tsx @@ -2,15 +2,10 @@ import React from 'react' import {View} from 'react-native' import {useLingui} from '@lingui/react' import {msg, Trans} from '@lingui/macro' -import Animated, {Easing, Layout} from 'react-native-reanimated' +import {LABELS} from '@atproto/api' import {atoms as a} from '#/alf' -import { - configurableAdultLabelGroups, - configurableOtherLabelGroups, - usePreferencesSetAdultContentMutation, -} from 'state/queries/preferences' -import {Divider} from '#/components/Divider' +import {usePreferencesSetAdultContentMutation} from 'state/queries/preferences' import {Button, ButtonIcon, ButtonText} from '#/components/Button' import {ChevronRight_Stroke2_Corner0_Rounded as ChevronRight} from '#/components/icons/Chevron' import {EyeSlash_Stroke2_Corner0_Rounded as EyeSlash} from '#/components/icons/EyeSlash' @@ -28,14 +23,6 @@ import {AdultContentEnabledPref} from '#/screens/Onboarding/StepModeration/Adult import {Context} from '#/screens/Onboarding/state' import {IconCircle} from '#/components/IconCircle' -function AnimatedDivider() { - return ( - <Animated.View layout={Layout.easing(Easing.ease).duration(200)}> - <Divider /> - </Animated.View> - ) -} - export function StepModeration() { const {_} = useLingui() const {track} = useAnalytics() @@ -52,7 +39,7 @@ export function StepModeration() { const adultContentEnabled = !!( (variables && variables.enabled) || - (!variables && preferences?.adultContentEnabled) + (!variables && preferences?.moderationPrefs.adultContentEnabled) ) const onContinue = React.useCallback(() => { @@ -86,22 +73,19 @@ export function StepModeration() { <AdultContentEnabledPref mutate={mutate} variables={variables} /> <View style={[a.gap_sm, a.w_full]}> - {adultContentEnabled && - configurableAdultLabelGroups.map((g, index) => ( - <React.Fragment key={index}> - {index === 0 && <AnimatedDivider />} - <ModerationOption labelGroup={g} isMounted={isMounted} /> - <AnimatedDivider /> - </React.Fragment> - ))} - - {configurableOtherLabelGroups.map((g, index) => ( - <React.Fragment key={index}> - {!adultContentEnabled && index === 0 && <AnimatedDivider />} - <ModerationOption labelGroup={g} isMounted={isMounted} /> - <AnimatedDivider /> - </React.Fragment> - ))} + <ModerationOption + labelValueDefinition={LABELS.porn} + disabled={!adultContentEnabled} + /> + <ModerationOption + labelValueDefinition={LABELS.sexual} + disabled={!adultContentEnabled} + /> + <ModerationOption + labelValueDefinition={LABELS['graphic-media']} + disabled={!adultContentEnabled} + /> + <ModerationOption labelValueDefinition={LABELS.nudity} /> </View> </> )} diff --git a/src/screens/Onboarding/StepSuggestedAccounts/SuggestedAccountCard.tsx b/src/screens/Onboarding/StepSuggestedAccounts/SuggestedAccountCard.tsx index 067005892..7e4ea1f8b 100644 --- a/src/screens/Onboarding/StepSuggestedAccounts/SuggestedAccountCard.tsx +++ b/src/screens/Onboarding/StepSuggestedAccounts/SuggestedAccountCard.tsx @@ -88,7 +88,7 @@ export function SuggestedAccountCard({ <UserAvatar size={48} avatar={profile.avatar} - moderation={moderation.avatar} + moderation={moderation.ui('avatar')} /> </View> <View style={[a.flex_1]}> diff --git a/src/screens/Onboarding/StepSuggestedAccounts/index.tsx b/src/screens/Onboarding/StepSuggestedAccounts/index.tsx index 14faddc10..bdf94d824 100644 --- a/src/screens/Onboarding/StepSuggestedAccounts/index.tsx +++ b/src/screens/Onboarding/StepSuggestedAccounts/index.tsx @@ -76,7 +76,7 @@ export function StepSuggestedAccounts() { return aggregateInterestItems( state.interestsStepResults.selectedInterests, state.interestsStepResults.apiResponse.suggestedAccountDids, - state.interestsStepResults.apiResponse.suggestedAccountDids.default, + state.interestsStepResults.apiResponse.suggestedAccountDids.default || [], ) }, [state.interestsStepResults]) const moderationOpts = useModerationOpts() diff --git a/src/screens/Onboarding/StepTopicalFeeds.tsx b/src/screens/Onboarding/StepTopicalFeeds.tsx index 636565e34..089363c23 100644 --- a/src/screens/Onboarding/StepTopicalFeeds.tsx +++ b/src/screens/Onboarding/StepTopicalFeeds.tsx @@ -21,7 +21,7 @@ import { import {FeedCard} from '#/screens/Onboarding/StepAlgoFeeds/FeedCard' import {aggregateInterestItems} from '#/screens/Onboarding/util' import {IconCircle} from '#/components/IconCircle' -import {IS_PROD_SERVICE} from 'lib/constants' +import {IS_TEST_USER} from 'lib/constants' import {useSession} from 'state/session' export function StepTopicalFeeds() { @@ -32,14 +32,14 @@ export function StepTopicalFeeds() { const [selectedFeedUris, setSelectedFeedUris] = React.useState<string[]>([]) const [saving, setSaving] = React.useState(false) const suggestedFeedUris = React.useMemo(() => { - if (!IS_PROD_SERVICE(currentAccount?.service)) return [] + if (IS_TEST_USER(currentAccount?.handle)) return [] return aggregateInterestItems( state.interestsStepResults.selectedInterests, state.interestsStepResults.apiResponse.suggestedFeedUris, - state.interestsStepResults.apiResponse.suggestedFeedUris.default, + state.interestsStepResults.apiResponse.suggestedFeedUris.default || [], ).slice(0, 10) }, [ - currentAccount?.service, + currentAccount?.handle, state.interestsStepResults.apiResponse.suggestedFeedUris, state.interestsStepResults.selectedInterests, ]) diff --git a/src/screens/Profile/ErrorState.tsx b/src/screens/Profile/ErrorState.tsx new file mode 100644 index 000000000..2ec2cf592 --- /dev/null +++ b/src/screens/Profile/ErrorState.tsx @@ -0,0 +1,72 @@ +import React from 'react' +import {View} from 'react-native' +import {Trans, msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {useNavigation} from '@react-navigation/native' + +import {useTheme, atoms as a} from '#/alf' +import {Text} from '#/components/Typography' +import {Button, ButtonText} from '#/components/Button' +import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo' +import {NavigationProp} from '#/lib/routes/types' + +export function ErrorState({error}: {error: string}) { + const t = useTheme() + const {_} = useLingui() + const navigation = useNavigation<NavigationProp>() + + const onPressBack = React.useCallback(() => { + if (navigation.canGoBack()) { + navigation.goBack() + } else { + navigation.navigate('Home') + } + }, [navigation]) + + return ( + <View style={[a.px_xl]}> + <CircleInfo width={48} style={[t.atoms.text_contrast_low]} /> + + <Text style={[a.text_xl, a.font_bold, a.pb_md, a.pt_xl]}> + <Trans>Hmmmm, we couldn't load that moderation service.</Trans> + </Text> + <Text + style={[ + a.text_md, + a.leading_normal, + a.pb_md, + t.atoms.text_contrast_medium, + ]}> + <Trans> + This moderation service is unavailable. See below for more details. If + this issue persists, contact us. + </Trans> + </Text> + <View + style={[ + a.relative, + a.py_md, + a.px_lg, + a.rounded_md, + a.mb_2xl, + t.atoms.bg_contrast_25, + ]}> + <Text style={[a.text_md, a.leading_normal]}>{error}</Text> + </View> + + <View style={{flexDirection: 'row'}}> + <Button + size="small" + color="secondary" + variant="solid" + label={_(msg`Go Back`)} + accessibilityHint="Return to previous page" + onPress={onPressBack}> + <ButtonText> + <Trans>Go Back</Trans> + </ButtonText> + </Button> + </View> + </View> + ) +} diff --git a/src/screens/Profile/Header/DisplayName.tsx b/src/screens/Profile/Header/DisplayName.tsx new file mode 100644 index 000000000..b6d88db71 --- /dev/null +++ b/src/screens/Profile/Header/DisplayName.tsx @@ -0,0 +1,31 @@ +import React from 'react' +import {View} from 'react-native' +import {AppBskyActorDefs, ModerationDecision} from '@atproto/api' +import {sanitizeHandle} from 'lib/strings/handles' +import {sanitizeDisplayName} from 'lib/strings/display-names' +import {Shadow} from '#/state/cache/types' + +import {atoms as a, useTheme} from '#/alf' +import {Text} from '#/components/Typography' + +export function ProfileHeaderDisplayName({ + profile, + moderation, +}: { + profile: Shadow<AppBskyActorDefs.ProfileViewDetailed> + moderation: ModerationDecision +}) { + const t = useTheme() + return ( + <View pointerEvents="none"> + <Text + testID="profileHeaderDisplayName" + style={[t.atoms.text, a.text_4xl, {fontWeight: '500'}]}> + {sanitizeDisplayName( + profile.displayName || sanitizeHandle(profile.handle), + moderation.ui('displayName'), + )} + </Text> + </View> + ) +} diff --git a/src/screens/Profile/Header/Handle.tsx b/src/screens/Profile/Header/Handle.tsx new file mode 100644 index 000000000..fd1cbe533 --- /dev/null +++ b/src/screens/Profile/Header/Handle.tsx @@ -0,0 +1,46 @@ +import React from 'react' +import {View} from 'react-native' +import {AppBskyActorDefs} from '@atproto/api' +import {isInvalidHandle} from 'lib/strings/handles' +import {Shadow} from '#/state/cache/types' +import {Trans} from '@lingui/macro' + +import {atoms as a, useTheme, web} from '#/alf' +import {Text} from '#/components/Typography' + +export function ProfileHeaderHandle({ + profile, +}: { + profile: Shadow<AppBskyActorDefs.ProfileViewDetailed> +}) { + const t = useTheme() + const invalidHandle = isInvalidHandle(profile.handle) + const blockHide = profile.viewer?.blocking || profile.viewer?.blockedBy + return ( + <View style={[a.flex_row, a.gap_xs, a.align_center]} pointerEvents="none"> + {profile.viewer?.followedBy && !blockHide ? ( + <View style={[t.atoms.bg_contrast_25, a.rounded_xs, a.px_sm, a.py_xs]}> + <Text style={[t.atoms.text, a.text_sm]}> + <Trans>Follows you</Trans> + </Text> + </View> + ) : undefined} + <Text + style={[ + invalidHandle + ? [ + a.border, + a.text_xs, + a.px_sm, + a.py_xs, + a.rounded_xs, + {borderColor: t.palette.contrast_200}, + ] + : [a.text_md, t.atoms.text_contrast_medium], + web({wordBreak: 'break-all'}), + ]}> + {invalidHandle ? <Trans>âš Invalid Handle</Trans> : `@${profile.handle}`} + </Text> + </View> + ) +} diff --git a/src/screens/Profile/Header/Metrics.tsx b/src/screens/Profile/Header/Metrics.tsx new file mode 100644 index 000000000..d9a8a01a8 --- /dev/null +++ b/src/screens/Profile/Header/Metrics.tsx @@ -0,0 +1,61 @@ +import React from 'react' +import {View} from 'react-native' +import {AppBskyActorDefs} from '@atproto/api' +import {Trans, msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' + +import {Shadow} from '#/state/cache/types' +import {pluralize} from '#/lib/strings/helpers' +import {makeProfileLink} from 'lib/routes/links' +import {formatCount} from 'view/com/util/numeric/format' + +import {atoms as a, useTheme} from '#/alf' +import {Text} from '#/components/Typography' +import {InlineLink} from '#/components/Link' + +export function ProfileHeaderMetrics({ + profile, +}: { + profile: Shadow<AppBskyActorDefs.ProfileViewDetailed> +}) { + const t = useTheme() + const {_} = useLingui() + const following = formatCount(profile.followsCount || 0) + const followers = formatCount(profile.followersCount || 0) + const pluralizedFollowers = pluralize(profile.followersCount || 0, 'follower') + + return ( + <View + style={[a.flex_row, a.gap_sm, a.align_center, a.pb_md]} + pointerEvents="box-none"> + <InlineLink + testID="profileHeaderFollowersButton" + style={[a.flex_row, t.atoms.text]} + to={makeProfileLink(profile, 'followers')} + label={`${followers} ${pluralizedFollowers}`}> + <Text style={[a.font_bold, a.text_md]}>{followers} </Text> + <Text style={[t.atoms.text_contrast_medium, a.text_md]}> + {pluralizedFollowers} + </Text> + </InlineLink> + <InlineLink + testID="profileHeaderFollowsButton" + style={[a.flex_row, t.atoms.text]} + to={makeProfileLink(profile, 'follows')} + label={_(msg`${following} following`)}> + <Trans> + <Text style={[a.font_bold, a.text_md]}>{following} </Text> + <Text style={[t.atoms.text_contrast_medium, a.text_md]}> + following + </Text> + </Trans> + </InlineLink> + <Text style={[a.font_bold, t.atoms.text, a.text_md]}> + {formatCount(profile.postsCount || 0)}{' '} + <Text style={[t.atoms.text_contrast_medium, a.font_normal, a.text_md]}> + {pluralize(profile.postsCount || 0, 'post')} + </Text> + </Text> + </View> + ) +} diff --git a/src/screens/Profile/Header/ProfileHeaderLabeler.tsx b/src/screens/Profile/Header/ProfileHeaderLabeler.tsx new file mode 100644 index 000000000..6722ed09b --- /dev/null +++ b/src/screens/Profile/Header/ProfileHeaderLabeler.tsx @@ -0,0 +1,329 @@ +import React, {memo, useMemo} from 'react' +import {View} from 'react-native' +import { + AppBskyActorDefs, + AppBskyLabelerDefs, + ModerationOpts, + moderateProfile, + RichText as RichTextAPI, +} from '@atproto/api' +import {Trans, msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' + +import {RichText} from '#/components/RichText' +import {useModalControls} from '#/state/modals' +import {usePreferencesQuery} from '#/state/queries/preferences' +import {useAnalytics} from 'lib/analytics/analytics' +import {useSession} from '#/state/session' +import {Shadow} from '#/state/cache/types' +import {useProfileShadow} from 'state/cache/profile-shadow' +import {useLabelerSubscriptionMutation} from '#/state/queries/labeler' +import {useLikeMutation, useUnlikeMutation} from '#/state/queries/like' +import {logger} from '#/logger' +import {Haptics} from '#/lib/haptics' +import {pluralize} from '#/lib/strings/helpers' +import {isAppLabeler} from '#/lib/moderation' + +import {atoms as a, useTheme, tokens} from '#/alf' +import {Button, ButtonText} from '#/components/Button' +import {Text} from '#/components/Typography' +import * as Toast from '#/view/com/util/Toast' +import {ProfileHeaderShell} from './Shell' +import {ProfileMenu} from '#/view/com/profile/ProfileMenu' +import {ProfileHeaderDisplayName} from './DisplayName' +import {ProfileHeaderHandle} from './Handle' +import {ProfileHeaderMetrics} from './Metrics' +import { + Heart2_Stroke2_Corner0_Rounded as Heart, + Heart2_Filled_Stroke2_Corner0_Rounded as HeartFilled, +} from '#/components/icons/Heart2' +import {DialogOuterProps} from '#/components/Dialog' +import * as Prompt from '#/components/Prompt' +import {Link} from '#/components/Link' + +interface Props { + profile: AppBskyActorDefs.ProfileViewDetailed + labeler: AppBskyLabelerDefs.LabelerViewDetailed + descriptionRT: RichTextAPI | null + moderationOpts: ModerationOpts + hideBackButton?: boolean + isPlaceholderProfile?: boolean +} + +let ProfileHeaderLabeler = ({ + profile: profileUnshadowed, + labeler, + descriptionRT, + moderationOpts, + hideBackButton = false, + isPlaceholderProfile, +}: Props): React.ReactNode => { + const profile: Shadow<AppBskyActorDefs.ProfileViewDetailed> = + useProfileShadow(profileUnshadowed) + const t = useTheme() + const {_} = useLingui() + const {currentAccount, hasSession} = useSession() + const {openModal} = useModalControls() + const {track} = useAnalytics() + const cantSubscribePrompt = Prompt.usePromptControl() + const isSelf = currentAccount?.did === profile.did + + const moderation = useMemo( + () => moderateProfile(profile, moderationOpts), + [profile, moderationOpts], + ) + const {data: preferences} = usePreferencesQuery() + const {mutateAsync: toggleSubscription, variables} = + useLabelerSubscriptionMutation() + const isSubscribed = + variables?.subscribe ?? + preferences?.moderationPrefs.labelers.find(l => l.did === profile.did) + const canSubscribe = + isSubscribed || + (preferences ? preferences?.moderationPrefs.labelers.length < 9 : false) + const {mutateAsync: likeMod, isPending: isLikePending} = useLikeMutation() + const {mutateAsync: unlikeMod, isPending: isUnlikePending} = + useUnlikeMutation() + const [likeUri, setLikeUri] = React.useState<string>( + labeler.viewer?.like || '', + ) + const [likeCount, setLikeCount] = React.useState(labeler.likeCount || 0) + + const onToggleLiked = React.useCallback(async () => { + if (!labeler) { + return + } + try { + Haptics.default() + + if (likeUri) { + await unlikeMod({uri: likeUri}) + track('CustomFeed:Unlike') + setLikeCount(c => c - 1) + setLikeUri('') + } else { + const res = await likeMod({uri: labeler.uri, cid: labeler.cid}) + track('CustomFeed:Like') + setLikeCount(c => c + 1) + setLikeUri(res.uri) + } + } catch (e: any) { + Toast.show( + _( + msg`There was an an issue contacting the server, please check your internet connection and try again.`, + ), + ) + logger.error(`Failed to toggle labeler like`, {message: e.message}) + } + }, [labeler, likeUri, likeMod, unlikeMod, track, _]) + + const onPressEditProfile = React.useCallback(() => { + track('ProfileHeader:EditProfileButtonClicked') + openModal({ + name: 'edit-profile', + profile, + }) + }, [track, openModal, profile]) + + const onPressSubscribe = React.useCallback(async () => { + if (!canSubscribe) { + cantSubscribePrompt.open() + return + } + try { + await toggleSubscription({ + did: profile.did, + subscribe: !isSubscribed, + }) + } catch (e: any) { + // setSubscriptionError(e.message) + logger.error(`Failed to subscribe to labeler`, {message: e.message}) + } + }, [ + toggleSubscription, + isSubscribed, + profile, + canSubscribe, + cantSubscribePrompt, + ]) + + const isMe = React.useMemo( + () => currentAccount?.did === profile.did, + [currentAccount, profile], + ) + + return ( + <ProfileHeaderShell + profile={profile} + moderation={moderation} + hideBackButton={hideBackButton} + isPlaceholderProfile={isPlaceholderProfile}> + <View style={[a.px_lg, a.pt_md, a.pb_sm]} pointerEvents="box-none"> + <View + style={[a.flex_row, a.justify_end, a.gap_sm, a.pb_lg]} + pointerEvents="box-none"> + {isMe ? ( + <Button + testID="profileHeaderEditProfileButton" + size="small" + color="secondary" + variant="solid" + onPress={onPressEditProfile} + label={_(msg`Edit profile`)} + style={a.rounded_full}> + <ButtonText> + <Trans>Edit Profile</Trans> + </ButtonText> + </Button> + ) : !isAppLabeler(profile.did) ? ( + <> + <Button + testID="toggleSubscribeBtn" + label={ + isSubscribed + ? _(msg`Unsubscribe from this labeler`) + : _(msg`Subscribe to this labeler`) + } + disabled={!hasSession} + onPress={onPressSubscribe}> + {state => ( + <View + style={[ + { + paddingVertical: 12, + backgroundColor: + isSubscribed || !canSubscribe + ? state.hovered || state.pressed + ? t.palette.contrast_50 + : t.palette.contrast_25 + : state.hovered || state.pressed + ? tokens.color.temp_purple_dark + : tokens.color.temp_purple, + }, + a.px_lg, + a.rounded_sm, + a.gap_sm, + ]}> + <Text + style={[ + { + color: canSubscribe + ? isSubscribed + ? t.palette.contrast_700 + : t.palette.white + : t.palette.contrast_400, + }, + a.font_bold, + a.text_center, + ]}> + {isSubscribed ? ( + <Trans>Unsubscribe</Trans> + ) : ( + <Trans>Subscribe to Labeler</Trans> + )} + </Text> + </View> + )} + </Button> + </> + ) : null} + <ProfileMenu profile={profile} /> + </View> + <View style={[a.flex_col, a.gap_xs, a.pb_md]}> + <ProfileHeaderDisplayName profile={profile} moderation={moderation} /> + <ProfileHeaderHandle profile={profile} /> + </View> + {!isPlaceholderProfile && ( + <> + {isSelf && <ProfileHeaderMetrics profile={profile} />} + {descriptionRT && !moderation.ui('profileView').blur ? ( + <View pointerEvents="auto"> + <RichText + testID="profileHeaderDescription" + style={[a.text_md]} + numberOfLines={15} + value={descriptionRT} + /> + </View> + ) : undefined} + {!isAppLabeler(profile.did) && ( + <View style={[a.flex_row, a.gap_xs, a.align_center, a.pt_lg]}> + <Button + testID="toggleLikeBtn" + size="small" + color="secondary" + variant="solid" + shape="round" + label={_(msg`Like this feed`)} + disabled={!hasSession || isLikePending || isUnlikePending} + onPress={onToggleLiked}> + {likeUri ? ( + <HeartFilled fill={t.palette.negative_400} /> + ) : ( + <Heart fill={t.atoms.text_contrast_medium.color} /> + )} + </Button> + + {typeof likeCount === 'number' && ( + <Link + to={{ + screen: 'ProfileLabelerLikedBy', + params: { + name: labeler.creator.handle || labeler.creator.did, + }, + }} + size="tiny" + label={_( + msg`Liked by ${likeCount} ${pluralize( + likeCount, + 'user', + )}`, + )}> + {({hovered, focused, pressed}) => ( + <Text + style={[ + a.font_bold, + a.text_sm, + t.atoms.text_contrast_medium, + (hovered || focused || pressed) && + t.atoms.text_contrast_high, + ]}> + <Trans> + Liked by {likeCount} {pluralize(likeCount, 'user')} + </Trans> + </Text> + )} + </Link> + )} + </View> + )} + </> + )} + </View> + <CantSubscribePrompt control={cantSubscribePrompt} /> + </ProfileHeaderShell> + ) +} +ProfileHeaderLabeler = memo(ProfileHeaderLabeler) +export {ProfileHeaderLabeler} + +function CantSubscribePrompt({ + control, +}: { + control: DialogOuterProps['control'] +}) { + return ( + <Prompt.Outer control={control}> + <Prompt.Title>Unable to subscribe</Prompt.Title> + <Prompt.Description> + <Trans> + We're sorry! You can only subscribe to ten labelers, and you've + reached your limit of ten. + </Trans> + </Prompt.Description> + <Prompt.Actions> + <Prompt.Action onPress={control.close}>OK</Prompt.Action> + </Prompt.Actions> + </Prompt.Outer> + ) +} diff --git a/src/screens/Profile/Header/ProfileHeaderStandard.tsx b/src/screens/Profile/Header/ProfileHeaderStandard.tsx new file mode 100644 index 000000000..8b9038244 --- /dev/null +++ b/src/screens/Profile/Header/ProfileHeaderStandard.tsx @@ -0,0 +1,286 @@ +import React, {memo, useMemo} from 'react' +import {View} from 'react-native' +import { + AppBskyActorDefs, + ModerationOpts, + moderateProfile, + RichText as RichTextAPI, +} from '@atproto/api' +import {Trans, msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' + +import {useModalControls} from '#/state/modals' +import {useAnalytics} from 'lib/analytics/analytics' +import {useSession, useRequireAuth} from '#/state/session' +import {Shadow} from '#/state/cache/types' +import {useProfileShadow} from 'state/cache/profile-shadow' +import { + useProfileFollowMutationQueue, + useProfileBlockMutationQueue, +} from '#/state/queries/profile' +import {logger} from '#/logger' +import {sanitizeDisplayName} from 'lib/strings/display-names' + +import {atoms as a, useTheme} from '#/alf' +import {Button, ButtonText, ButtonIcon} from '#/components/Button' +import * as Toast from '#/view/com/util/Toast' +import {ProfileHeaderShell} from './Shell' +import {ProfileMenu} from '#/view/com/profile/ProfileMenu' +import {ProfileHeaderDisplayName} from './DisplayName' +import {ProfileHeaderHandle} from './Handle' +import {ProfileHeaderMetrics} from './Metrics' +import {ProfileHeaderSuggestedFollows} from '#/view/com/profile/ProfileHeaderSuggestedFollows' +import {RichText} from '#/components/RichText' +import * as Prompt from '#/components/Prompt' +import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check' +import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus' + +interface Props { + profile: AppBskyActorDefs.ProfileViewDetailed + descriptionRT: RichTextAPI | null + moderationOpts: ModerationOpts + hideBackButton?: boolean + isPlaceholderProfile?: boolean +} + +let ProfileHeaderStandard = ({ + profile: profileUnshadowed, + descriptionRT, + moderationOpts, + hideBackButton = false, + isPlaceholderProfile, +}: Props): React.ReactNode => { + const profile: Shadow<AppBskyActorDefs.ProfileViewDetailed> = + useProfileShadow(profileUnshadowed) + const t = useTheme() + const {currentAccount, hasSession} = useSession() + const {_} = useLingui() + const {openModal} = useModalControls() + const {track} = useAnalytics() + const moderation = useMemo( + () => moderateProfile(profile, moderationOpts), + [profile, moderationOpts], + ) + const [showSuggestedFollows, setShowSuggestedFollows] = React.useState(false) + const [queueFollow, queueUnfollow] = useProfileFollowMutationQueue( + profile, + 'ProfileHeader', + ) + const [_queueBlock, queueUnblock] = useProfileBlockMutationQueue(profile) + const unblockPromptControl = Prompt.usePromptControl() + const requireAuth = useRequireAuth() + + const onPressEditProfile = React.useCallback(() => { + track('ProfileHeader:EditProfileButtonClicked') + openModal({ + name: 'edit-profile', + profile, + }) + }, [track, openModal, profile]) + + const onPressFollow = () => { + requireAuth(async () => { + try { + track('ProfileHeader:FollowButtonClicked') + await queueFollow() + Toast.show( + _( + msg`Following ${sanitizeDisplayName( + profile.displayName || profile.handle, + moderation.ui('displayName'), + )}`, + ), + ) + } catch (e: any) { + if (e?.name !== 'AbortError') { + logger.error('Failed to follow', {message: String(e)}) + Toast.show(_(msg`There was an issue! ${e.toString()}`)) + } + } + }) + } + + const onPressUnfollow = () => { + requireAuth(async () => { + try { + track('ProfileHeader:UnfollowButtonClicked') + await queueUnfollow() + Toast.show( + _( + msg`No longer following ${sanitizeDisplayName( + profile.displayName || profile.handle, + moderation.ui('displayName'), + )}`, + ), + ) + } catch (e: any) { + if (e?.name !== 'AbortError') { + logger.error('Failed to unfollow', {message: String(e)}) + Toast.show(_(msg`There was an issue! ${e.toString()}`)) + } + } + }) + } + + const unblockAccount = React.useCallback(async () => { + track('ProfileHeader:UnblockAccountButtonClicked') + try { + await queueUnblock() + Toast.show(_(msg`Account unblocked`)) + } catch (e: any) { + if (e?.name !== 'AbortError') { + logger.error('Failed to unblock account', {message: e}) + Toast.show(_(msg`There was an issue! ${e.toString()}`)) + } + } + }, [_, queueUnblock, track]) + + const isMe = React.useMemo( + () => currentAccount?.did === profile.did, + [currentAccount, profile], + ) + + return ( + <ProfileHeaderShell + profile={profile} + moderation={moderation} + hideBackButton={hideBackButton} + isPlaceholderProfile={isPlaceholderProfile}> + <View style={[a.px_lg, a.pt_md, a.pb_sm]} pointerEvents="box-none"> + <View + style={[a.flex_row, a.justify_end, a.gap_sm, a.pb_sm]} + pointerEvents="box-none"> + {isMe ? ( + <Button + testID="profileHeaderEditProfileButton" + size="small" + color="secondary" + variant="solid" + onPress={onPressEditProfile} + label={_(msg`Edit profile`)} + style={a.rounded_full}> + <ButtonText> + <Trans>Edit Profile</Trans> + </ButtonText> + </Button> + ) : profile.viewer?.blocking ? ( + profile.viewer?.blockingByList ? null : ( + <Button + testID="unblockBtn" + size="small" + color="secondary" + variant="solid" + label={_(msg`Unblock`)} + disabled={!hasSession} + onPress={() => unblockPromptControl.open()} + style={a.rounded_full}> + <ButtonText> + <Trans context="action">Unblock</Trans> + </ButtonText> + </Button> + ) + ) : !profile.viewer?.blockedBy ? ( + <> + {hasSession && ( + <Button + testID="suggestedFollowsBtn" + size="small" + color={showSuggestedFollows ? 'primary' : 'secondary'} + variant="solid" + shape="round" + onPress={() => setShowSuggestedFollows(!showSuggestedFollows)} + label={_(msg`Show follows similar to ${profile.handle}`)}> + <FontAwesomeIcon + icon="user-plus" + style={ + showSuggestedFollows + ? {color: t.palette.white} + : t.atoms.text + } + size={14} + /> + </Button> + )} + + <Button + testID={profile.viewer?.following ? 'unfollowBtn' : 'followBtn'} + size="small" + color={profile.viewer?.following ? 'secondary' : 'primary'} + variant="solid" + label={ + profile.viewer?.following + ? _(msg`Unfollow ${profile.handle}`) + : _(msg`Follow ${profile.handle}`) + } + disabled={!hasSession} + onPress={ + profile.viewer?.following ? onPressUnfollow : onPressFollow + } + style={[a.rounded_full, a.gap_xs]}> + <ButtonIcon + position="left" + icon={profile.viewer?.following ? Check : Plus} + /> + <ButtonText> + {profile.viewer?.following ? ( + <Trans>Following</Trans> + ) : ( + <Trans>Follow</Trans> + )} + </ButtonText> + </Button> + </> + ) : null} + <ProfileMenu profile={profile} /> + </View> + <View style={[a.flex_col, a.gap_xs, a.pb_sm]}> + <ProfileHeaderDisplayName profile={profile} moderation={moderation} /> + <ProfileHeaderHandle profile={profile} /> + </View> + {!isPlaceholderProfile && ( + <> + <ProfileHeaderMetrics profile={profile} /> + {descriptionRT && !moderation.ui('profileView').blur ? ( + <View pointerEvents="auto"> + <RichText + testID="profileHeaderDescription" + style={[a.text_md]} + numberOfLines={15} + value={descriptionRT} + /> + </View> + ) : undefined} + </> + )} + </View> + {showSuggestedFollows && ( + <ProfileHeaderSuggestedFollows + actorDid={profile.did} + requestDismiss={() => { + if (showSuggestedFollows) { + setShowSuggestedFollows(false) + } else { + track('ProfileHeader:SuggestedFollowsOpened') + setShowSuggestedFollows(true) + } + }} + /> + )} + <Prompt.Basic + control={unblockPromptControl} + title={_(msg`Unblock Account?`)} + description={_( + msg`The account will be able to interact with you after unblocking.`, + )} + onConfirm={unblockAccount} + confirmButtonCta={ + profile.viewer?.blocking ? _(msg`Unblock`) : _(msg`Block`) + } + confirmButtonColor="negative" + /> + </ProfileHeaderShell> + ) +} +ProfileHeaderStandard = memo(ProfileHeaderStandard) +export {ProfileHeaderStandard} diff --git a/src/screens/Profile/Header/Shell.tsx b/src/screens/Profile/Header/Shell.tsx new file mode 100644 index 000000000..c470cb286 --- /dev/null +++ b/src/screens/Profile/Header/Shell.tsx @@ -0,0 +1,164 @@ +import React, {memo} from 'react' +import {StyleSheet, TouchableWithoutFeedback, View} from 'react-native' +import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import {useNavigation} from '@react-navigation/native' +import {AppBskyActorDefs, ModerationDecision} from '@atproto/api' +import {msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {NavigationProp} from 'lib/routes/types' +import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' +import {BACK_HITSLOP} from 'lib/constants' +import {useSession} from '#/state/session' +import {Shadow} from '#/state/cache/types' +import {useLightboxControls, ProfileImageLightbox} from '#/state/lightbox' + +import {atoms as a, useTheme} from '#/alf' +import {LabelsOnMe} from '#/components/moderation/LabelsOnMe' +import {BlurView} from 'view/com/util/BlurView' +import {LoadingPlaceholder} from 'view/com/util/LoadingPlaceholder' +import {UserAvatar} from 'view/com/util/UserAvatar' +import {UserBanner} from 'view/com/util/UserBanner' +import {ProfileHeaderAlerts} from '#/components/moderation/ProfileHeaderAlerts' + +interface Props { + profile: Shadow<AppBskyActorDefs.ProfileViewDetailed> + moderation: ModerationDecision + hideBackButton?: boolean + isPlaceholderProfile?: boolean +} + +let ProfileHeaderShell = ({ + children, + profile, + moderation, + hideBackButton = false, + isPlaceholderProfile, +}: React.PropsWithChildren<Props>): React.ReactNode => { + const t = useTheme() + const {currentAccount} = useSession() + const {_} = useLingui() + const {openLightbox} = useLightboxControls() + const navigation = useNavigation<NavigationProp>() + const {isDesktop} = useWebMediaQueries() + + const onPressBack = React.useCallback(() => { + if (navigation.canGoBack()) { + navigation.goBack() + } else { + navigation.navigate('Home') + } + }, [navigation]) + + const onPressAvi = React.useCallback(() => { + const modui = moderation.ui('avatar') + if (profile.avatar && !(modui.blur && modui.noOverride)) { + openLightbox(new ProfileImageLightbox(profile)) + } + }, [openLightbox, profile, moderation]) + + const isMe = React.useMemo( + () => currentAccount?.did === profile.did, + [currentAccount, profile], + ) + + return ( + <View style={t.atoms.bg} pointerEvents="box-none"> + <View pointerEvents="none"> + {isPlaceholderProfile ? ( + <LoadingPlaceholder + width="100%" + height={150} + style={{borderRadius: 0}} + /> + ) : ( + <UserBanner + type={profile.associated?.labeler ? 'labeler' : 'default'} + banner={profile.banner} + moderation={moderation.ui('banner')} + /> + )} + </View> + + {children} + + <View style={[a.px_lg, a.pb_sm]} pointerEvents="box-none"> + <ProfileHeaderAlerts moderation={moderation} /> + {isMe && ( + <LabelsOnMe details={{did: profile.did}} labels={profile.labels} /> + )} + </View> + + {!isDesktop && !hideBackButton && ( + <TouchableWithoutFeedback + testID="profileHeaderBackBtn" + onPress={onPressBack} + hitSlop={BACK_HITSLOP} + accessibilityRole="button" + accessibilityLabel={_(msg`Back`)} + accessibilityHint=""> + <View style={styles.backBtnWrapper}> + <BlurView style={styles.backBtn} blurType="dark"> + <FontAwesomeIcon size={18} icon="angle-left" color="white" /> + </BlurView> + </View> + </TouchableWithoutFeedback> + )} + <TouchableWithoutFeedback + testID="profileHeaderAviButton" + onPress={onPressAvi} + accessibilityRole="image" + accessibilityLabel={_(msg`View ${profile.handle}'s avatar`)} + accessibilityHint=""> + <View + style={[ + t.atoms.bg, + {borderColor: t.atoms.bg.backgroundColor}, + styles.avi, + profile.associated?.labeler && styles.aviLabeler, + ]}> + <UserAvatar + type={profile.associated?.labeler ? 'labeler' : 'user'} + size={90} + avatar={profile.avatar} + moderation={moderation.ui('avatar')} + /> + </View> + </TouchableWithoutFeedback> + </View> + ) +} +ProfileHeaderShell = memo(ProfileHeaderShell) +export {ProfileHeaderShell} + +const styles = StyleSheet.create({ + backBtnWrapper: { + position: 'absolute', + top: 10, + left: 10, + width: 30, + height: 30, + overflow: 'hidden', + borderRadius: 15, + // @ts-ignore web only + cursor: 'pointer', + }, + backBtn: { + width: 30, + height: 30, + borderRadius: 15, + alignItems: 'center', + justifyContent: 'center', + }, + avi: { + position: 'absolute', + top: 110, + left: 10, + width: 94, + height: 94, + borderRadius: 47, + borderWidth: 2, + }, + aviLabeler: { + borderRadius: 10, + }, +}) diff --git a/src/screens/Profile/Header/index.tsx b/src/screens/Profile/Header/index.tsx new file mode 100644 index 000000000..1280dd8b1 --- /dev/null +++ b/src/screens/Profile/Header/index.tsx @@ -0,0 +1,78 @@ +import React, {memo} from 'react' +import {StyleSheet, View} from 'react-native' +import { + AppBskyActorDefs, + AppBskyLabelerDefs, + ModerationOpts, + RichText as RichTextAPI, +} from '@atproto/api' +import {LoadingPlaceholder} from 'view/com/util/LoadingPlaceholder' +import {usePalette} from 'lib/hooks/usePalette' + +import {ProfileHeaderStandard} from './ProfileHeaderStandard' +import {ProfileHeaderLabeler} from './ProfileHeaderLabeler' + +let ProfileHeaderLoading = (_props: {}): React.ReactNode => { + const pal = usePalette('default') + return ( + <View style={pal.view}> + <LoadingPlaceholder width="100%" height={150} style={{borderRadius: 0}} /> + <View + style={[pal.view, {borderColor: pal.colors.background}, styles.avi]}> + <LoadingPlaceholder width={80} height={80} style={styles.br40} /> + </View> + <View style={styles.content}> + <View style={[styles.buttonsLine]}> + <LoadingPlaceholder width={167} height={31} style={styles.br50} /> + </View> + </View> + </View> + ) +} +ProfileHeaderLoading = memo(ProfileHeaderLoading) +export {ProfileHeaderLoading} + +interface Props { + profile: AppBskyActorDefs.ProfileViewDetailed + labeler: AppBskyLabelerDefs.LabelerViewDetailed | undefined + descriptionRT: RichTextAPI | null + moderationOpts: ModerationOpts + hideBackButton?: boolean + isPlaceholderProfile?: boolean +} + +let ProfileHeader = (props: Props): React.ReactNode => { + if (props.profile.associated?.labeler) { + if (!props.labeler) { + return <ProfileHeaderLoading /> + } + return <ProfileHeaderLabeler {...props} labeler={props.labeler} /> + } + return <ProfileHeaderStandard {...props} /> +} +ProfileHeader = memo(ProfileHeader) +export {ProfileHeader} + +const styles = StyleSheet.create({ + avi: { + position: 'absolute', + top: 110, + left: 10, + width: 84, + height: 84, + borderRadius: 42, + borderWidth: 2, + }, + content: { + paddingTop: 8, + paddingHorizontal: 14, + paddingBottom: 4, + }, + buttonsLine: { + flexDirection: 'row', + marginLeft: 'auto', + marginBottom: 12, + }, + br40: {borderRadius: 40}, + br50: {borderRadius: 50}, +}) diff --git a/src/screens/Profile/ProfileLabelerLikedBy.tsx b/src/screens/Profile/ProfileLabelerLikedBy.tsx new file mode 100644 index 000000000..1d2167520 --- /dev/null +++ b/src/screens/Profile/ProfileLabelerLikedBy.tsx @@ -0,0 +1,46 @@ +import React from 'react' +import {View} from 'react-native' +import {msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {useFocusEffect} from '@react-navigation/native' + +import {NativeStackScreenProps, CommonNavigatorParams} from '#/lib/routes/types' +import {ViewHeader} from '#/view/com/util/ViewHeader' +import {LikedByList} from '#/components/LikedByList' +import {useSetMinimalShellMode} from '#/state/shell' +import {makeRecordUri} from '#/lib/strings/url-helpers' + +import {atoms as a, useBreakpoints} from '#/alf' + +export function ProfileLabelerLikedByScreen({ + route, +}: NativeStackScreenProps<CommonNavigatorParams, 'ProfileLabelerLikedBy'>) { + const setMinimalShellMode = useSetMinimalShellMode() + const {name: handleOrDid} = route.params + const uri = makeRecordUri(handleOrDid, 'app.bsky.labeler.service', 'self') + const {_} = useLingui() + const {gtMobile} = useBreakpoints() + + useFocusEffect( + React.useCallback(() => { + setMinimalShellMode(false) + }, [setMinimalShellMode]), + ) + + return ( + <View + style={[ + a.mx_auto, + a.w_full, + a.h_full_vh, + gtMobile && [ + { + maxWidth: 600, + }, + ], + ]}> + <ViewHeader title={_(msg`Liked By`)} /> + <LikedByList uri={uri} /> + </View> + ) +} diff --git a/src/screens/Profile/Sections/Feed.tsx b/src/screens/Profile/Sections/Feed.tsx new file mode 100644 index 000000000..0a5e2208d --- /dev/null +++ b/src/screens/Profile/Sections/Feed.tsx @@ -0,0 +1,88 @@ +import React from 'react' +import {View} from 'react-native' +import {msg, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {ListRef} from 'view/com/util/List' +import {Feed} from 'view/com/posts/Feed' +import {EmptyState} from 'view/com/util/EmptyState' +import {FeedDescriptor} from '#/state/queries/post-feed' +import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed' +import {LoadLatestBtn} from 'view/com/util/load-latest/LoadLatestBtn' +import {useQueryClient} from '@tanstack/react-query' +import {truncateAndInvalidate} from '#/state/queries/util' +import {Text} from '#/view/com/util/text/Text' +import {usePalette} from 'lib/hooks/usePalette' +import {isNative} from '#/platform/detection' +import {SectionRef} from './types' + +interface FeedSectionProps { + feed: FeedDescriptor + headerHeight: number + isFocused: boolean + scrollElRef: ListRef + ignoreFilterFor?: string +} +export const ProfileFeedSection = React.forwardRef< + SectionRef, + FeedSectionProps +>(function FeedSectionImpl( + {feed, headerHeight, isFocused, scrollElRef, ignoreFilterFor}, + ref, +) { + const {_} = useLingui() + const queryClient = useQueryClient() + const [hasNew, setHasNew] = React.useState(false) + const [isScrolledDown, setIsScrolledDown] = React.useState(false) + + const onScrollToTop = React.useCallback(() => { + scrollElRef.current?.scrollToOffset({ + animated: isNative, + offset: -headerHeight, + }) + truncateAndInvalidate(queryClient, FEED_RQKEY(feed)) + setHasNew(false) + }, [scrollElRef, headerHeight, queryClient, feed, setHasNew]) + React.useImperativeHandle(ref, () => ({ + scrollToTop: onScrollToTop, + })) + + const renderPostsEmpty = React.useCallback(() => { + return <EmptyState icon="feed" message={_(msg`This feed is empty!`)} /> + }, [_]) + + return ( + <View> + <Feed + testID="postsFeed" + enabled={isFocused} + feed={feed} + scrollElRef={scrollElRef} + onHasNew={setHasNew} + onScrolledDownChange={setIsScrolledDown} + renderEmptyState={renderPostsEmpty} + headerOffset={headerHeight} + renderEndOfFeed={ProfileEndOfFeed} + ignoreFilterFor={ignoreFilterFor} + /> + {(isScrolledDown || hasNew) && ( + <LoadLatestBtn + onPress={onScrollToTop} + label={_(msg`Load new posts`)} + showIndicator={hasNew} + /> + )} + </View> + ) +}) + +function ProfileEndOfFeed() { + const pal = usePalette('default') + + return ( + <View style={[pal.border, {paddingTop: 32, borderTopWidth: 1}]}> + <Text style={[pal.textLight, pal.border, {textAlign: 'center'}]}> + <Trans>End of feed</Trans> + </Text> + </View> + ) +} diff --git a/src/screens/Profile/Sections/Labels.tsx b/src/screens/Profile/Sections/Labels.tsx new file mode 100644 index 000000000..08db4a861 --- /dev/null +++ b/src/screens/Profile/Sections/Labels.tsx @@ -0,0 +1,215 @@ +import React from 'react' +import {View} from 'react-native' +import { + AppBskyLabelerDefs, + ModerationOpts, + interpretLabelValueDefinitions, + InterpretedLabelValueDefinition, +} from '@atproto/api' +import {Trans, msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {useSafeAreaFrame} from 'react-native-safe-area-context' + +import {useScrollHandlers} from '#/lib/ScrollContext' +import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED' +import {isLabelerSubscribed, lookupLabelValueDefinition} from '#/lib/moderation' +import {ListRef} from '#/view/com/util/List' +import {SectionRef} from './types' +import {isNative} from '#/platform/detection' + +import {useTheme, atoms as a} from '#/alf' +import {Text} from '#/components/Typography' +import {Loader} from '#/components/Loader' +import {Divider} from '#/components/Divider' +import {CenteredView, ScrollView} from '#/view/com/util/Views' +import {ErrorState} from '../ErrorState' +import {ModerationLabelPref} from '#/components/moderation/ModerationLabelPref' +import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo' + +interface LabelsSectionProps { + isLabelerLoading: boolean + labelerInfo: AppBskyLabelerDefs.LabelerViewDetailed | undefined + labelerError: Error | null + moderationOpts: ModerationOpts + scrollElRef: ListRef + headerHeight: number +} +export const ProfileLabelsSection = React.forwardRef< + SectionRef, + LabelsSectionProps +>(function LabelsSectionImpl( + { + isLabelerLoading, + labelerInfo, + labelerError, + moderationOpts, + scrollElRef, + headerHeight, + }, + ref, +) { + const {_} = useLingui() + const {height: minHeight} = useSafeAreaFrame() + + const onScrollToTop = React.useCallback(() => { + // @ts-ignore TODO fix this + scrollElRef.current?.scrollTo({ + animated: isNative, + x: 0, + y: -headerHeight, + }) + }, [scrollElRef, headerHeight]) + + React.useImperativeHandle(ref, () => ({ + scrollToTop: onScrollToTop, + })) + + return ( + <CenteredView style={{flex: 1, minHeight}} sideBorders> + {isLabelerLoading ? ( + <View style={[a.w_full, a.align_center]}> + <Loader size="xl" /> + </View> + ) : labelerError || !labelerInfo ? ( + <ErrorState + error={ + labelerError?.toString() || + _(msg`Something went wrong, please try again.`) + } + /> + ) : ( + <ProfileLabelsSectionInner + moderationOpts={moderationOpts} + labelerInfo={labelerInfo} + scrollElRef={scrollElRef} + headerHeight={headerHeight} + /> + )} + </CenteredView> + ) +}) + +export function ProfileLabelsSectionInner({ + moderationOpts, + labelerInfo, + scrollElRef, + headerHeight, +}: { + moderationOpts: ModerationOpts + labelerInfo: AppBskyLabelerDefs.LabelerViewDetailed + scrollElRef: ListRef + headerHeight: number +}) { + const t = useTheme() + const contextScrollHandlers = useScrollHandlers() + + const scrollHandler = useAnimatedScrollHandler({ + onBeginDrag(e, ctx) { + contextScrollHandlers.onBeginDrag?.(e, ctx) + }, + onEndDrag(e, ctx) { + contextScrollHandlers.onEndDrag?.(e, ctx) + }, + onScroll(e, ctx) { + contextScrollHandlers.onScroll?.(e, ctx) + }, + }) + + const {labelValues} = labelerInfo.policies + const isSubscribed = isLabelerSubscribed(labelerInfo, moderationOpts) + const labelDefs = React.useMemo(() => { + const customDefs = interpretLabelValueDefinitions(labelerInfo) + return labelValues + .map(val => lookupLabelValueDefinition(val, customDefs)) + .filter( + def => def && def?.configurable, + ) as InterpretedLabelValueDefinition[] + }, [labelerInfo, labelValues]) + + return ( + <ScrollView + // @ts-ignore TODO fix this + ref={scrollElRef} + scrollEventThrottle={1} + contentContainerStyle={{ + paddingTop: headerHeight, + borderWidth: 0, + }} + contentOffset={{x: 0, y: headerHeight * -1}} + onScroll={scrollHandler}> + <View style={[a.pt_xl, a.px_lg, a.border_t, t.atoms.border_contrast_low]}> + <View> + <Text style={[t.atoms.text_contrast_high, a.leading_snug, a.text_sm]}> + <Trans> + Labels are annotations on users and content. They can be used to + hide, warn, and categorize the network. + </Trans> + </Text> + {labelerInfo.creator.viewer?.blocking ? ( + <View style={[a.flex_row, a.gap_sm, a.align_center, a.mt_md]}> + <CircleInfo size="sm" fill={t.atoms.text_contrast_medium.color} /> + <Text + style={[t.atoms.text_contrast_high, a.leading_snug, a.text_sm]}> + <Trans> + Blocking does not prevent this labeler from placing labels on + your account. + </Trans> + </Text> + </View> + ) : null} + {labelValues.length === 0 ? ( + <Text + style={[ + a.pt_xl, + t.atoms.text_contrast_high, + a.leading_snug, + a.text_sm, + ]}> + <Trans> + This labeler hasn't declared what labels it publishes, and may + not be active. + </Trans> + </Text> + ) : !isSubscribed ? ( + <Text + style={[ + a.pt_xl, + t.atoms.text_contrast_high, + a.leading_snug, + a.text_sm, + ]}> + <Trans> + Subscribe to @{labelerInfo.creator.handle} to use these labels: + </Trans> + </Text> + ) : null} + </View> + {labelDefs.length > 0 && ( + <View + style={[ + a.mt_xl, + a.w_full, + a.rounded_md, + a.overflow_hidden, + t.atoms.bg_contrast_25, + ]}> + {labelDefs.map((labelDef, i) => { + return ( + <React.Fragment key={labelDef.identifier}> + {i !== 0 && <Divider />} + <ModerationLabelPref + disabled={isSubscribed ? undefined : true} + labelValueDefinition={labelDef} + labelerDid={labelerInfo.creator.did} + /> + </React.Fragment> + ) + })} + </View> + )} + + <View style={{height: 400}} /> + </View> + </ScrollView> + ) +} diff --git a/src/screens/Profile/Sections/types.ts b/src/screens/Profile/Sections/types.ts new file mode 100644 index 000000000..a7f77d648 --- /dev/null +++ b/src/screens/Profile/Sections/types.ts @@ -0,0 +1,3 @@ +export interface SectionRef { + scrollToTop: () => void +} diff --git a/src/state/modals/index.tsx b/src/state/modals/index.tsx index 691add005..524dcb1ba 100644 --- a/src/state/modals/index.tsx +++ b/src/state/modals/index.tsx @@ -1,6 +1,5 @@ import React from 'react' -import {AppBskyActorDefs, AppBskyGraphDefs, ModerationUI} from '@atproto/api' -import {StyleProp, ViewStyle} from 'react-native' +import {AppBskyActorDefs, AppBskyGraphDefs} from '@atproto/api' import {Image as RNImage} from 'react-native-image-crop-picker' import {ImageModel} from '#/state/models/media/image' @@ -9,49 +8,12 @@ import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' import {EmbedPlayerSource} from '#/lib/strings/embed-player' import {ThreadgateSetting} from '../queries/threadgate' -export interface ConfirmModal { - name: 'confirm' - title: string - message: string | (() => JSX.Element) - onPressConfirm: () => void | Promise<void> - onPressCancel?: () => void | Promise<void> - confirmBtnText?: string - confirmBtnStyle?: StyleProp<ViewStyle> - cancelBtnText?: string -} - export interface EditProfileModal { name: 'edit-profile' profile: AppBskyActorDefs.ProfileViewDetailed onUpdate?: () => void } -export interface ModerationDetailsModal { - name: 'moderation-details' - context: 'account' | 'content' - moderation: ModerationUI -} - -export type ReportModal = { - name: 'report' -} & ( - | { - uri: string - cid: string - } - | {did: string} -) - -export type AppealLabelModal = { - name: 'appeal-label' -} & ( - | { - uri: string - cid: string - } - | {did: string} -) - export interface CreateOrEditListModal { name: 'create-or-edit-list' purpose?: string @@ -135,10 +97,6 @@ export interface AddAppPasswordModal { name: 'add-app-password' } -export interface ContentFilteringSettingsModal { - name: 'content-filtering-settings' -} - export interface ContentLanguagesSettingsModal { name: 'content-languages-settings' } @@ -147,10 +105,6 @@ export interface PostLanguagesSettingsModal { name: 'post-languages-settings' } -export interface BirthDateSettingsModal { - name: 'birth-date-settings' -} - export interface VerifyEmailModal { name: 'verify-email' showReminder?: boolean @@ -191,22 +145,15 @@ export type Modal = | ChangeHandleModal | DeleteAccountModal | EditProfileModal - | BirthDateSettingsModal | VerifyEmailModal | ChangeEmailModal | ChangePasswordModal | SwitchAccountModal // Curation - | ContentFilteringSettingsModal | ContentLanguagesSettingsModal | PostLanguagesSettingsModal - // Moderation - | ModerationDetailsModal - | ReportModal - | AppealLabelModal - // Lists | CreateOrEditListModal | UserAddRemoveListsModal @@ -225,7 +172,6 @@ export type Modal = | InviteCodesModal // Generic - | ConfirmModal | LinkWarningModal | EmbedConsentModal | InAppBrowserConsentModal diff --git a/src/state/preferences/index.tsx b/src/state/preferences/index.tsx index a442b763a..cf1d90151 100644 --- a/src/state/preferences/index.tsx +++ b/src/state/preferences/index.tsx @@ -15,6 +15,7 @@ export { useSetExternalEmbedPref, } from './external-embeds-prefs' export * from './hidden-posts' +export {useLabelDefinitions} from './label-defs' export function Provider({children}: React.PropsWithChildren<{}>) { return ( diff --git a/src/state/preferences/label-defs.tsx b/src/state/preferences/label-defs.tsx new file mode 100644 index 000000000..d60f8ccb8 --- /dev/null +++ b/src/state/preferences/label-defs.tsx @@ -0,0 +1,25 @@ +import React from 'react' +import {InterpretedLabelValueDefinition, AppBskyLabelerDefs} from '@atproto/api' +import {useLabelDefinitionsQuery} from '../queries/preferences' + +interface StateContext { + labelDefs: Record<string, InterpretedLabelValueDefinition[]> + labelers: AppBskyLabelerDefs.LabelerViewDetailed[] +} + +const stateContext = React.createContext<StateContext>({ + labelDefs: {}, + labelers: [], +}) + +export function Provider({children}: React.PropsWithChildren<{}>) { + const {labelDefs, labelers} = useLabelDefinitionsQuery() + + const state = {labelDefs, labelers} + + return <stateContext.Provider value={state}>{children}</stateContext.Provider> +} + +export function useLabelDefinitions() { + return React.useContext(stateContext) +} diff --git a/src/state/queries/actor-autocomplete.ts b/src/state/queries/actor-autocomplete.ts index 3159ad7aa..e6bf04ba3 100644 --- a/src/state/queries/actor-autocomplete.ts +++ b/src/state/queries/actor-autocomplete.ts @@ -6,17 +6,14 @@ import {logger} from '#/logger' import {getAgent} from '#/state/session' import {useMyFollowsQuery} from '#/state/queries/my-follows' import {STALE} from '#/state/queries' -import { - DEFAULT_LOGGED_OUT_PREFERENCES, - getModerationOpts, - useModerationOpts, -} from './preferences' +import {DEFAULT_LOGGED_OUT_PREFERENCES, useModerationOpts} from './preferences' import {isInvalidHandle} from '#/lib/strings/handles' +import {isJustAMute} from '#/lib/moderation' -const DEFAULT_MOD_OPTS = getModerationOpts({ - userDid: '', - preferences: DEFAULT_LOGGED_OUT_PREFERENCES, -}) +const DEFAULT_MOD_OPTS = { + userDid: undefined, + prefs: DEFAULT_LOGGED_OUT_PREFERENCES.moderationPrefs, +} export const RQKEY = (prefix: string) => ['actor-autocomplete', prefix] @@ -104,18 +101,12 @@ function computeSuggestions( } for (const item of searched) { if (!items.find(item2 => item2.handle === item.handle)) { - items.push({ - did: item.did, - handle: item.handle, - displayName: item.displayName, - avatar: item.avatar, - labels: item.labels, - }) + items.push(item) } } return items.filter(profile => { - const mod = moderateProfile(profile, moderationOpts) - return !mod.account.filter && mod.account.cause?.type !== 'muted' + const modui = moderateProfile(profile, moderationOpts).ui('profileList') + return !modui.filter || isJustAMute(modui) }) } diff --git a/src/state/queries/labeler.ts b/src/state/queries/labeler.ts new file mode 100644 index 000000000..b2f93c4a4 --- /dev/null +++ b/src/state/queries/labeler.ts @@ -0,0 +1,89 @@ +import {z} from 'zod' +import {useQuery, useMutation, useQueryClient} from '@tanstack/react-query' +import {AppBskyLabelerDefs} from '@atproto/api' + +import {getAgent} from '#/state/session' +import {preferencesQueryKey} from '#/state/queries/preferences' +import {STALE} from '#/state/queries' + +export const labelerInfoQueryKey = (did: string) => ['labeler-info', did] +export const labelersInfoQueryKey = (dids: string[]) => [ + 'labelers-info', + dids.sort(), +] +export const labelersDetailedInfoQueryKey = (dids: string[]) => [ + 'labelers-detailed-info', + dids, +] + +export function useLabelerInfoQuery({ + did, + enabled, +}: { + did?: string + enabled?: boolean +}) { + return useQuery({ + enabled: !!did && enabled !== false, + queryKey: labelerInfoQueryKey(did as string), + queryFn: async () => { + const res = await getAgent().app.bsky.labeler.getServices({ + dids: [did as string], + detailed: true, + }) + return res.data.views[0] as AppBskyLabelerDefs.LabelerViewDetailed + }, + }) +} + +export function useLabelersInfoQuery({dids}: {dids: string[]}) { + return useQuery({ + enabled: !!dids.length, + queryKey: labelersInfoQueryKey(dids), + queryFn: async () => { + const res = await getAgent().app.bsky.labeler.getServices({dids}) + return res.data.views as AppBskyLabelerDefs.LabelerView[] + }, + }) +} + +export function useLabelersDetailedInfoQuery({dids}: {dids: string[]}) { + return useQuery({ + enabled: !!dids.length, + queryKey: labelersDetailedInfoQueryKey(dids), + gcTime: 1000 * 60 * 60 * 6, // 6 hours + staleTime: STALE.MINUTES.ONE, + queryFn: async () => { + const res = await getAgent().app.bsky.labeler.getServices({ + dids, + detailed: true, + }) + return res.data.views as AppBskyLabelerDefs.LabelerViewDetailed[] + }, + }) +} + +export function useLabelerSubscriptionMutation() { + const queryClient = useQueryClient() + + return useMutation({ + async mutationFn({did, subscribe}: {did: string; subscribe: boolean}) { + // TODO + z.object({ + did: z.string(), + subscribe: z.boolean(), + }).parse({did, subscribe}) + + if (subscribe) { + await getAgent().addLabeler(did) + } else { + await getAgent().removeLabeler(did) + } + }, + onSuccess() { + queryClient.invalidateQueries({ + queryKey: preferencesQueryKey, + }) + }, + }) +} diff --git a/src/state/queries/notifications/util.ts b/src/state/queries/notifications/util.ts index 626d3e911..97fc57dc1 100644 --- a/src/state/queries/notifications/util.ts +++ b/src/state/queries/notifications/util.ts @@ -1,14 +1,13 @@ import { AppBskyNotificationListNotifications, ModerationOpts, - moderateProfile, + moderateNotification, AppBskyFeedDefs, AppBskyFeedPost, AppBskyFeedRepost, AppBskyFeedLike, AppBskyEmbedRecord, } from '@atproto/api' -import {moderatePost_wrapped as moderatePost} from '#/lib/moderatePost_wrapped' import chunk from 'lodash.chunk' import {QueryClient} from '@tanstack/react-query' import {getAgent} from '../../session' @@ -88,37 +87,20 @@ export async function fetchPage({ // internal methods // = -// TODO this should be in the sdk as moderateNotification -prf -function shouldFilterNotif( +export function shouldFilterNotif( notif: AppBskyNotificationListNotifications.Notification, moderationOpts: ModerationOpts | undefined, ): boolean { if (!moderationOpts) { return false } - const profile = moderateProfile(notif.author, moderationOpts) - if ( - profile.account.filter || - profile.profile.filter || - notif.author.viewer?.muted - ) { - return true - } - if ( - notif.type === 'reply' || - notif.type === 'quote' || - notif.type === 'mention' - ) { - // NOTE: the notification overlaps the post enough for this to work - const post = moderatePost(notif, moderationOpts) - if (post.content.filter) { - return true - } + if (notif.author.viewer?.following) { + return false } - return false + return moderateNotification(notif, moderationOpts).ui('contentList').filter } -function groupNotifications( +export function groupNotifications( notifs: AppBskyNotificationListNotifications.Notification[], ): FeedNotification[] { const groupedNotifs: FeedNotification[] = [] diff --git a/src/state/queries/post-feed.ts b/src/state/queries/post-feed.ts index c295ffcb0..0e6eef52c 100644 --- a/src/state/queries/post-feed.ts +++ b/src/state/queries/post-feed.ts @@ -3,8 +3,8 @@ import {AppState} from 'react-native' import { AppBskyFeedDefs, AppBskyFeedPost, + ModerationDecision, AtUri, - PostModeration, } from '@atproto/api' import { useInfiniteQuery, @@ -29,7 +29,6 @@ import {STALE} from '#/state/queries' import {precacheFeedPostProfiles} from './profile' import {getAgent} from '#/state/session' import {DEFAULT_LOGGED_OUT_PREFERENCES} from '#/state/queries/preferences/const' -import {getModerationOpts} from '#/state/queries/preferences/moderation' import {KnownError} from '#/view/com/posts/FeedErrorMessage' import {embedViewRecordToPostView, getEmbeddedPost} from './util' import {useModerationOpts} from './preferences' @@ -69,7 +68,7 @@ export interface FeedPostSliceItem { post: AppBskyFeedDefs.PostView record: AppBskyFeedPost.Record reason?: AppBskyFeedDefs.ReasonRepost | ReasonFeedSource - moderation: PostModeration + moderation: ModerationDecision } export interface FeedPostSlice { @@ -250,9 +249,17 @@ export function usePostFeedQuery( // apply moderation filter for (let i = 0; i < slice.items.length; i++) { + const ignoreFilter = + slice.items[i].post.author.did === ignoreFilterFor + if (ignoreFilter) { + // remove mutes to avoid confused UIs + moderations[i].causes = moderations[i].causes.filter( + cause => cause.type !== 'muted', + ) + } if ( - moderations[i]?.content.filter && - slice.items[i].post.author.did !== ignoreFilterFor + !ignoreFilter && + moderations[i]?.ui('contentList').filter ) { return undefined } @@ -435,13 +442,12 @@ function assertSomePostsPassModeration(feed: AppBskyFeedDefs.FeedViewPost[]) { let somePostsPassModeration = false for (const item of feed) { - const moderationOpts = getModerationOpts({ - userDid: '', - preferences: DEFAULT_LOGGED_OUT_PREFERENCES, + const moderation = moderatePost(item.post, { + userDid: undefined, + prefs: DEFAULT_LOGGED_OUT_PREFERENCES.moderationPrefs, }) - const moderation = moderatePost(item.post, moderationOpts) - if (!moderation.content.filter) { + if (!moderation.ui('contentList').filter) { // we have a sfw post somePostsPassModeration = true } diff --git a/src/state/queries/post-liked-by.ts b/src/state/queries/post-liked-by.ts index 2cde07f28..a0498ada4 100644 --- a/src/state/queries/post-liked-by.ts +++ b/src/state/queries/post-liked-by.ts @@ -12,9 +12,9 @@ const PAGE_SIZE = 30 type RQPageParam = string | undefined // TODO refactor invalidate on mutate? -export const RQKEY = (resolvedUri: string) => ['post-liked-by', resolvedUri] +export const RQKEY = (resolvedUri: string) => ['liked-by', resolvedUri] -export function usePostLikedByQuery(resolvedUri: string | undefined) { +export function useLikedByQuery(resolvedUri: string | undefined) { return useInfiniteQuery< AppBskyFeedGetLikes.OutputSchema, Error, diff --git a/src/state/queries/post.ts b/src/state/queries/post.ts index eb59f7da4..e3682e304 100644 --- a/src/state/queries/post.ts +++ b/src/state/queries/post.ts @@ -5,6 +5,7 @@ import {Shadow} from '#/state/cache/types' import {getAgent} from '#/state/session' import {updatePostShadow} from '#/state/cache/post-shadow' import {track} from '#/lib/analytics/analytics' +import {logEvent, LogEvents} from '#/lib/statsig/statsig' import {useToggleMutationQueue} from '#/lib/hooks/useToggleMutationQueue' export const RQKEY = (postUri: string) => ['post', postUri] @@ -58,12 +59,14 @@ export function useGetPost() { export function usePostLikeMutationQueue( post: Shadow<AppBskyFeedDefs.PostView>, + logContext: LogEvents['post:like']['logContext'] & + LogEvents['post:unlike']['logContext'], ) { const postUri = post.uri const postCid = post.cid const initialLikeUri = post.viewer?.like - const likeMutation = usePostLikeMutation() - const unlikeMutation = usePostUnlikeMutation() + const likeMutation = usePostLikeMutation(logContext) + const unlikeMutation = usePostUnlikeMutation(logContext) const queueToggle = useToggleMutationQueue({ initialState: initialLikeUri, @@ -111,22 +114,30 @@ export function usePostLikeMutationQueue( return [queueLike, queueUnlike] } -function usePostLikeMutation() { +function usePostLikeMutation(logContext: LogEvents['post:like']['logContext']) { return useMutation< {uri: string}, // responds with the uri of the like Error, {uri: string; cid: string} // the post's uri and cid >({ - mutationFn: post => getAgent().like(post.uri, post.cid), + mutationFn: post => { + logEvent('post:like', {logContext}) + return getAgent().like(post.uri, post.cid) + }, onSuccess() { track('Post:Like') }, }) } -function usePostUnlikeMutation() { +function usePostUnlikeMutation( + logContext: LogEvents['post:unlike']['logContext'], +) { return useMutation<void, Error, {postUri: string; likeUri: string}>({ - mutationFn: ({likeUri}) => getAgent().deleteLike(likeUri), + mutationFn: ({likeUri}) => { + logEvent('post:unlike', {logContext}) + return getAgent().deleteLike(likeUri) + }, onSuccess() { track('Post:Unlike') }, @@ -135,12 +146,14 @@ function usePostUnlikeMutation() { export function usePostRepostMutationQueue( post: Shadow<AppBskyFeedDefs.PostView>, + logContext: LogEvents['post:repost']['logContext'] & + LogEvents['post:unrepost']['logContext'], ) { const postUri = post.uri const postCid = post.cid const initialRepostUri = post.viewer?.repost - const repostMutation = usePostRepostMutation() - const unrepostMutation = usePostUnrepostMutation() + const repostMutation = usePostRepostMutation(logContext) + const unrepostMutation = usePostUnrepostMutation(logContext) const queueToggle = useToggleMutationQueue({ initialState: initialRepostUri, @@ -188,22 +201,32 @@ export function usePostRepostMutationQueue( return [queueRepost, queueUnrepost] } -function usePostRepostMutation() { +function usePostRepostMutation( + logContext: LogEvents['post:repost']['logContext'], +) { return useMutation< {uri: string}, // responds with the uri of the repost Error, {uri: string; cid: string} // the post's uri and cid >({ - mutationFn: post => getAgent().repost(post.uri, post.cid), + mutationFn: post => { + logEvent('post:repost', {logContext}) + return getAgent().repost(post.uri, post.cid) + }, onSuccess() { track('Post:Repost') }, }) } -function usePostUnrepostMutation() { +function usePostUnrepostMutation( + logContext: LogEvents['post:unrepost']['logContext'], +) { return useMutation<void, Error, {postUri: string; repostUri: string}>({ - mutationFn: ({repostUri}) => getAgent().deleteRepost(repostUri), + mutationFn: ({repostUri}) => { + logEvent('post:unrepost', {logContext}) + return getAgent().deleteRepost(repostUri) + }, onSuccess() { track('Post:Unrepost') }, diff --git a/src/state/queries/preferences/const.ts b/src/state/queries/preferences/const.ts index 53c9e482a..4cb4d1e96 100644 --- a/src/state/queries/preferences/const.ts +++ b/src/state/queries/preferences/const.ts @@ -29,26 +29,20 @@ export const DEFAULT_PROD_FEEDS = { export const DEFAULT_LOGGED_OUT_PREFERENCES: UsePreferencesQueryResponse = { birthDate: new Date('2022-11-17'), // TODO(pwi) - adultContentEnabled: false, feeds: { saved: [], pinned: [], unpinned: [], }, - // labels are undefined until set by user - contentLabels: { - nsfw: DEFAULT_LOGGED_OUT_LABEL_PREFERENCES.nsfw, - nudity: DEFAULT_LOGGED_OUT_LABEL_PREFERENCES.nudity, - suggestive: DEFAULT_LOGGED_OUT_LABEL_PREFERENCES.suggestive, - gore: DEFAULT_LOGGED_OUT_LABEL_PREFERENCES.gore, - hate: DEFAULT_LOGGED_OUT_LABEL_PREFERENCES.hate, - spam: DEFAULT_LOGGED_OUT_LABEL_PREFERENCES.spam, - impersonation: DEFAULT_LOGGED_OUT_LABEL_PREFERENCES.impersonation, + moderationPrefs: { + adultContentEnabled: false, + labels: DEFAULT_LOGGED_OUT_LABEL_PREFERENCES, + labelers: [], + mutedWords: [], + hiddenPosts: [], }, feedViewPrefs: DEFAULT_HOME_FEED_PREFS, threadViewPrefs: DEFAULT_THREAD_VIEW_PREFS, userAge: 13, // TODO(pwi) interests: {tags: []}, - mutedWords: [], - hiddenPosts: [], } diff --git a/src/state/queries/preferences/index.ts b/src/state/queries/preferences/index.ts index 37ef10ae0..f9cd59cda 100644 --- a/src/state/queries/preferences/index.ts +++ b/src/state/queries/preferences/index.ts @@ -1,29 +1,29 @@ -import {useMemo} from 'react' +import {useMemo, createContext, useContext} from 'react' import {useQuery, useMutation, useQueryClient} from '@tanstack/react-query' import { LabelPreference, BskyFeedViewPreference, + ModerationOpts, AppBskyActorDefs, + BSKY_LABELER_DID, } from '@atproto/api' import {track} from '#/lib/analytics/analytics' import {getAge} from '#/lib/strings/time' -import {useSession, getAgent} from '#/state/session' -import {DEFAULT_LABEL_PREFERENCES} from '#/state/queries/preferences/moderation' +import {getAgent, useSession} from '#/state/session' import { - ConfigurableLabelGroup, UsePreferencesQueryResponse, ThreadViewPreferences, } from '#/state/queries/preferences/types' -import {temp__migrateLabelPref} from '#/state/queries/preferences/util' import { DEFAULT_HOME_FEED_PREFS, DEFAULT_THREAD_VIEW_PREFS, DEFAULT_LOGGED_OUT_PREFERENCES, } from '#/state/queries/preferences/const' -import {getModerationOpts} from '#/state/queries/preferences/moderation' +import {DEFAULT_LOGGED_OUT_LABEL_PREFERENCES} from '#/state/queries/preferences/moderation' import {STALE} from '#/state/queries' -import {useHiddenPosts} from '#/state/preferences/hidden-posts' +import {useHiddenPosts, useLabelDefinitions} from '#/state/preferences' +import {saveLabelers} from '#/state/session/agent-config' export * from '#/state/queries/preferences/types' export * from '#/state/queries/preferences/moderation' @@ -44,6 +44,13 @@ export function usePreferencesQuery() { return DEFAULT_LOGGED_OUT_PREFERENCES } else { const res = await agent.getPreferences() + + // save to local storage to ensure there are labels on initial requests + saveLabelers( + agent.session.did, + res.moderationPrefs.labelers.map(l => l.did), + ) + const preferences: UsePreferencesQueryResponse = { ...res, feeds: { @@ -54,32 +61,6 @@ export function usePreferencesQuery() { return !res.feeds.pinned?.includes(f) }) || [], }, - // labels are undefined until set by user - contentLabels: { - nsfw: temp__migrateLabelPref( - res.contentLabels?.nsfw || DEFAULT_LABEL_PREFERENCES.nsfw, - ), - nudity: temp__migrateLabelPref( - res.contentLabels?.nudity || DEFAULT_LABEL_PREFERENCES.nudity, - ), - suggestive: temp__migrateLabelPref( - res.contentLabels?.suggestive || - DEFAULT_LABEL_PREFERENCES.suggestive, - ), - gore: temp__migrateLabelPref( - res.contentLabels?.gore || DEFAULT_LABEL_PREFERENCES.gore, - ), - hate: temp__migrateLabelPref( - res.contentLabels?.hate || DEFAULT_LABEL_PREFERENCES.hate, - ), - spam: temp__migrateLabelPref( - res.contentLabels?.spam || DEFAULT_LABEL_PREFERENCES.spam, - ), - impersonation: temp__migrateLabelPref( - res.contentLabels?.impersonation || - DEFAULT_LABEL_PREFERENCES.impersonation, - ), - }, feedViewPrefs: { ...DEFAULT_HOME_FEED_PREFS, ...(res.feedViewPrefs.home || {}), @@ -96,25 +77,41 @@ export function usePreferencesQuery() { }) } +// used in the moderation state devtool +export const moderationOptsOverrideContext = createContext< + ModerationOpts | undefined +>(undefined) + export function useModerationOpts() { + const override = useContext(moderationOptsOverrideContext) const {currentAccount} = useSession() const prefs = usePreferencesQuery() - const hiddenPosts = useHiddenPosts() - const opts = useMemo(() => { + const {labelDefs} = useLabelDefinitions() + const hiddenPosts = useHiddenPosts() // TODO move this into pds-stored prefs + const opts = useMemo<ModerationOpts | undefined>(() => { + if (override) { + return override + } if (!prefs.data) { return } - const moderationOpts = getModerationOpts({ - userDid: currentAccount?.did || '', - preferences: prefs.data, - }) - return { - ...moderationOpts, - hiddenPosts, - mutedWords: prefs.data.mutedWords || [], + userDid: currentAccount?.did, + prefs: { + ...prefs.data.moderationPrefs, + labelers: prefs.data.moderationPrefs.labelers.length + ? prefs.data.moderationPrefs.labelers + : [ + { + did: BSKY_LABELER_DID, + labels: DEFAULT_LOGGED_OUT_LABEL_PREFERENCES, + }, + ], + hiddenPosts: hiddenPosts || [], + }, + labelDefs, } - }, [currentAccount?.did, prefs.data, hiddenPosts]) + }, [override, currentAccount, labelDefs, prefs.data, hiddenPosts]) return opts } @@ -138,10 +135,32 @@ export function usePreferencesSetContentLabelMutation() { return useMutation< void, unknown, - {labelGroup: ConfigurableLabelGroup; visibility: LabelPreference} + {label: string; visibility: LabelPreference; labelerDid: string | undefined} >({ - mutationFn: async ({labelGroup, visibility}) => { - await getAgent().setContentLabelPref(labelGroup, visibility) + mutationFn: async ({label, visibility, labelerDid}) => { + await getAgent().setContentLabelPref(label, visibility, labelerDid) + // triggers a refetch + await queryClient.invalidateQueries({ + queryKey: preferencesQueryKey, + }) + }, + }) +} + +export function useSetContentLabelMutation() { + const queryClient = useQueryClient() + + return useMutation({ + mutationFn: async ({ + label, + visibility, + labelerDid, + }: { + label: string + visibility: LabelPreference + labelerDid?: string + }) => { + await getAgent().setContentLabelPref(label, visibility, labelerDid) // triggers a refetch await queryClient.invalidateQueries({ queryKey: preferencesQueryKey, diff --git a/src/state/queries/preferences/moderation.ts b/src/state/queries/preferences/moderation.ts index cdae52937..9cd183e8b 100644 --- a/src/state/queries/preferences/moderation.ts +++ b/src/state/queries/preferences/moderation.ts @@ -1,181 +1,53 @@ +import React from 'react' import { - LabelPreference, - ComAtprotoLabelDefs, - ModerationOpts, + DEFAULT_LABEL_SETTINGS, + BskyAgent, + interpretLabelValueDefinitions, } from '@atproto/api' -import { - LabelGroup, - ConfigurableLabelGroup, - UsePreferencesQueryResponse, -} from '#/state/queries/preferences/types' - -export type Label = ComAtprotoLabelDefs.Label - -export type LabelGroupConfig = { - id: LabelGroup - title: string - isAdultImagery?: boolean - subtitle?: string - warning: string - values: string[] -} - -export const DEFAULT_LABEL_PREFERENCES: Record< - ConfigurableLabelGroup, - LabelPreference -> = { - nsfw: 'hide', - nudity: 'warn', - suggestive: 'warn', - gore: 'warn', - hate: 'hide', - spam: 'hide', - impersonation: 'hide', -} +import {usePreferencesQuery} from './index' +import {useLabelersDetailedInfoQuery} from '../labeler' /** * More strict than our default settings for logged in users. - * - * TODO(pwi) */ -export const DEFAULT_LOGGED_OUT_LABEL_PREFERENCES: Record< - ConfigurableLabelGroup, - LabelPreference -> = { - nsfw: 'hide', - nudity: 'hide', - suggestive: 'hide', - gore: 'hide', - hate: 'hide', - spam: 'hide', - impersonation: 'hide', -} - -export const ILLEGAL_LABEL_GROUP: LabelGroupConfig = { - id: 'illegal', - title: 'Illegal Content', - warning: 'Illegal Content', - values: ['csam', 'dmca-violation', 'nudity-nonconsensual'], -} - -export const ALWAYS_FILTER_LABEL_GROUP: LabelGroupConfig = { - id: 'always-filter', - title: 'Content Warning', - warning: 'Content Warning', - values: ['!filter'], -} - -export const ALWAYS_WARN_LABEL_GROUP: LabelGroupConfig = { - id: 'always-warn', - title: 'Content Warning', - warning: 'Content Warning', - values: ['!warn', 'account-security'], -} - -export const UNKNOWN_LABEL_GROUP: LabelGroupConfig = { - id: 'unknown', - title: 'Unknown Label', - warning: 'Content Warning', - values: [], -} - -export const CONFIGURABLE_LABEL_GROUPS: Record< - ConfigurableLabelGroup, - LabelGroupConfig -> = { - nsfw: { - id: 'nsfw', - title: 'Explicit Sexual Images', - subtitle: 'i.e. pornography', - warning: 'Sexually Explicit', - values: ['porn', 'nsfl'], - isAdultImagery: true, - }, - nudity: { - id: 'nudity', - title: 'Other Nudity', - subtitle: 'Including non-sexual and artistic', - warning: 'Nudity', - values: ['nudity'], - isAdultImagery: true, - }, - suggestive: { - id: 'suggestive', - title: 'Sexually Suggestive', - subtitle: 'Does not include nudity', - warning: 'Sexually Suggestive', - values: ['sexual'], - isAdultImagery: true, - }, - gore: { - id: 'gore', - title: 'Violent / Bloody', - subtitle: 'Gore, self-harm, torture', - warning: 'Violence', - values: ['gore', 'self-harm', 'torture', 'nsfl', 'corpse'], - isAdultImagery: true, - }, - hate: { - id: 'hate', - title: 'Hate Group Iconography', - subtitle: 'Images of terror groups, articles covering events, etc.', - warning: 'Hate Groups', - values: ['icon-kkk', 'icon-nazi', 'icon-intolerant', 'behavior-intolerant'], - }, - spam: { - id: 'spam', - title: 'Spam', - subtitle: 'Excessive unwanted interactions', - warning: 'Spam', - values: ['spam'], - }, - impersonation: { - id: 'impersonation', - title: 'Impersonation', - subtitle: 'Accounts falsely claiming to be people or orgs', - warning: 'Impersonation', - values: ['impersonation'], - }, -} - -export function getModerationOpts({ - userDid, - preferences, -}: { - userDid: string - preferences: UsePreferencesQueryResponse -}): ModerationOpts { - return { - userDid: userDid, - adultContentEnabled: preferences.adultContentEnabled, - labels: { - porn: preferences.contentLabels.nsfw, - sexual: preferences.contentLabels.suggestive, - nudity: preferences.contentLabels.nudity, - nsfl: preferences.contentLabels.gore, - corpse: preferences.contentLabels.gore, - gore: preferences.contentLabels.gore, - torture: preferences.contentLabels.gore, - 'self-harm': preferences.contentLabels.gore, - 'intolerant-race': preferences.contentLabels.hate, - 'intolerant-gender': preferences.contentLabels.hate, - 'intolerant-sexual-orientation': preferences.contentLabels.hate, - 'intolerant-religion': preferences.contentLabels.hate, - intolerant: preferences.contentLabels.hate, - 'icon-intolerant': preferences.contentLabels.hate, - spam: preferences.contentLabels.spam, - impersonation: preferences.contentLabels.impersonation, - scam: 'warn', - }, - labelers: [ - { - labeler: { - did: '', - displayName: 'Bluesky Social', - }, - labels: {}, - }, - ], - } +export const DEFAULT_LOGGED_OUT_LABEL_PREFERENCES: typeof DEFAULT_LABEL_SETTINGS = + Object.fromEntries( + Object.entries(DEFAULT_LABEL_SETTINGS).map(([key, _pref]) => [key, 'hide']), + ) + +export function useMyLabelersQuery() { + const prefs = usePreferencesQuery() + const dids = Array.from( + new Set( + BskyAgent.appLabelers.concat( + prefs.data?.moderationPrefs.labelers.map(l => l.did) || [], + ), + ), + ) + const labelers = useLabelersDetailedInfoQuery({dids}) + const isLoading = prefs.isLoading || labelers.isLoading + const error = prefs.error || labelers.error + return React.useMemo(() => { + return { + isLoading, + error, + data: labelers.data, + } + }, [labelers, isLoading, error]) +} + +export function useLabelDefinitionsQuery() { + const labelers = useMyLabelersQuery() + return React.useMemo(() => { + return { + labelDefs: Object.fromEntries( + (labelers.data || []).map(labeler => [ + labeler.creator.did, + interpretLabelValueDefinitions(labeler), + ]), + ), + labelers: labelers.data || [], + } + }, [labelers]) } diff --git a/src/state/queries/preferences/types.ts b/src/state/queries/preferences/types.ts index 45c9eed7d..96da16f1a 100644 --- a/src/state/queries/preferences/types.ts +++ b/src/state/queries/preferences/types.ts @@ -1,46 +1,13 @@ import { BskyPreferences, - LabelPreference, BskyThreadViewPreference, BskyFeedViewPreference, } from '@atproto/api' -export const configurableAdultLabelGroups = [ - 'nsfw', - 'nudity', - 'suggestive', - 'gore', -] as const - -export const configurableOtherLabelGroups = [ - 'hate', - 'spam', - 'impersonation', -] as const - -export const configurableLabelGroups = [ - ...configurableAdultLabelGroups, - ...configurableOtherLabelGroups, -] as const -export type ConfigurableLabelGroup = (typeof configurableLabelGroups)[number] - -export type LabelGroup = - | ConfigurableLabelGroup - | 'illegal' - | 'always-filter' - | 'always-warn' - | 'unknown' - export type UsePreferencesQueryResponse = Omit< BskyPreferences, 'contentLabels' | 'feedViewPrefs' | 'feeds' > & { - /* - * Content labels previously included 'show', which has been deprecated in - * favor of 'ignore'. The API can return legacy data from the database, and - * we clean up the data in `usePreferencesQuery`. - */ - contentLabels: Record<ConfigurableLabelGroup, LabelPreference> feedViewPrefs: BskyFeedViewPreference & { lab_mergeFeedEnabled?: boolean } diff --git a/src/state/queries/preferences/util.ts b/src/state/queries/preferences/util.ts deleted file mode 100644 index 7b8160c28..000000000 --- a/src/state/queries/preferences/util.ts +++ /dev/null @@ -1,16 +0,0 @@ -import {LabelPreference} from '@atproto/api' - -/** - * Content labels previously included 'show', which has been deprecated in - * favor of 'ignore'. The API can return legacy data from the database, and - * we clean up the data in `usePreferencesQuery`. - * - * @deprecated - */ -export function temp__migrateLabelPref( - pref: LabelPreference | 'show', -): LabelPreference { - // @ts-ignore - if (pref === 'show') return 'ignore' - return pref -} diff --git a/src/state/queries/profile-extra-info.ts b/src/state/queries/profile-extra-info.ts deleted file mode 100644 index 8fc32c33e..000000000 --- a/src/state/queries/profile-extra-info.ts +++ /dev/null @@ -1,34 +0,0 @@ -import {useQuery} from '@tanstack/react-query' - -import {getAgent} from '#/state/session' -import {STALE} from '#/state/queries' - -// TODO refactor invalidate on mutate? -export const RQKEY = (did: string) => ['profile-extra-info', did] - -/** - * Fetches some additional information for the profile screen which - * is not available in the API's ProfileView - */ -export function useProfileExtraInfoQuery(did: string) { - return useQuery({ - staleTime: STALE.MINUTES.ONE, - queryKey: RQKEY(did), - async queryFn() { - const [listsRes, feedsRes] = await Promise.all([ - getAgent().app.bsky.graph.getLists({ - actor: did, - limit: 1, - }), - getAgent().app.bsky.feed.getActorFeeds({ - actor: did, - limit: 1, - }), - ]) - return { - hasLists: listsRes.data.lists.length > 0, - hasFeedgens: feedsRes.data.feeds.length > 0, - } - }, - }) -} diff --git a/src/state/queries/profile.ts b/src/state/queries/profile.ts index e81ea0f3f..3c9e3e41c 100644 --- a/src/state/queries/profile.ts +++ b/src/state/queries/profile.ts @@ -26,6 +26,7 @@ import {RQKEY as RQKEY_MY_MUTED} from './my-muted-accounts' import {RQKEY as RQKEY_MY_BLOCKED} from './my-blocked-accounts' import {STALE} from '#/state/queries' import {track} from '#/lib/analytics/analytics' +import {logEvent, LogEvents} from '#/lib/statsig/statsig' import {ThreadNode} from './post-thread' export const RQKEY = (did: string) => ['profile', did] @@ -186,11 +187,13 @@ export function useProfileUpdateMutation() { export function useProfileFollowMutationQueue( profile: Shadow<AppBskyActorDefs.ProfileViewDetailed>, + logContext: LogEvents['profile:follow']['logContext'] & + LogEvents['profile:unfollow']['logContext'], ) { const did = profile.did const initialFollowingUri = profile.viewer?.following - const followMutation = useProfileFollowMutation() - const unfollowMutation = useProfileUnfollowMutation() + const followMutation = useProfileFollowMutation(logContext) + const unfollowMutation = useProfileUnfollowMutation(logContext) const queueToggle = useToggleMutationQueue({ initialState: initialFollowingUri, @@ -237,9 +240,12 @@ export function useProfileFollowMutationQueue( return [queueFollow, queueUnfollow] } -function useProfileFollowMutation() { +function useProfileFollowMutation( + logContext: LogEvents['profile:follow']['logContext'], +) { return useMutation<{uri: string; cid: string}, Error, {did: string}>({ mutationFn: async ({did}) => { + logEvent('profile:follow', {logContext}) return await getAgent().follow(did) }, onSuccess(data, variables) { @@ -248,9 +254,12 @@ function useProfileFollowMutation() { }) } -function useProfileUnfollowMutation() { +function useProfileUnfollowMutation( + logContext: LogEvents['profile:unfollow']['logContext'], +) { return useMutation<void, Error, {did: string; followUri: string}>({ mutationFn: async ({followUri}) => { + logEvent('profile:unfollow', {logContext}) track('Profile:Unfollow', {username: followUri}) return await getAgent().deleteFollow(followUri) }, diff --git a/src/state/queries/suggested-follows.ts b/src/state/queries/suggested-follows.ts index 932226b75..45b3ebb62 100644 --- a/src/state/queries/suggested-follows.ts +++ b/src/state/queries/suggested-follows.ts @@ -46,7 +46,8 @@ export function useSuggestedFollowsQuery() { res.data.actors = res.data.actors .filter( - actor => !moderateProfile(actor, moderationOpts!).account.filter, + actor => + !moderateProfile(actor, moderationOpts!).ui('profileList').filter, ) .filter(actor => { const viewer = actor.viewer diff --git a/src/state/session/agent-config.ts b/src/state/session/agent-config.ts new file mode 100644 index 000000000..3ee2718a3 --- /dev/null +++ b/src/state/session/agent-config.ts @@ -0,0 +1,12 @@ +import AsyncStorage from '@react-native-async-storage/async-storage' + +const PREFIX = 'agent-labelers' + +export async function saveLabelers(did: string, value: string[]) { + await AsyncStorage.setItem(`${PREFIX}:${did}`, JSON.stringify(value)) +} + +export async function readLabelers(did: string): Promise<string[] | undefined> { + const rawData = await AsyncStorage.getItem(`${PREFIX}:${did}`) + return rawData ? JSON.parse(rawData) : undefined +} diff --git a/src/state/session/index.tsx b/src/state/session/index.tsx index 46628318c..6b1474839 100644 --- a/src/state/session/index.tsx +++ b/src/state/session/index.tsx @@ -1,8 +1,15 @@ import React from 'react' -import {BskyAgent, AtpPersistSessionHandler} from '@atproto/api' +import { + BskyAgent, + AtpPersistSessionHandler, + BSKY_LABELER_DID, +} from '@atproto/api' import {useQueryClient} from '@tanstack/react-query' import {jwtDecode} from 'jwt-decode' +import {IS_DEV} from '#/env' +import {IS_TEST_USER} from '#/lib/constants' +import {isWeb} from '#/platform/detection' import {networkRetry} from '#/lib/async/retry' import {logger} from '#/logger' import * as persisted from '#/state/persisted' @@ -12,6 +19,7 @@ import {useLoggedOutViewControls} from '#/state/shell/logged-out' import {useCloseAllActiveElements} from '#/state/util' import {track} from '#/lib/analytics/analytics' import {hasProp} from '#/lib/type-guards' +import {readLabelers} from './agent-config' let __globalAgent: BskyAgent = PUBLIC_BSKY_AGENT @@ -255,6 +263,8 @@ export function Provider({children}: React.PropsWithChildren<{}>) { deactivated, } + await configureModeration(agent, account) + agent.setPersistSessionHandler( createPersistSessionHandler( account, @@ -298,6 +308,8 @@ export function Provider({children}: React.PropsWithChildren<{}>) { deactivated: isSessionDeactivated(agent.session.accessJwt), } + await configureModeration(agent, account) + agent.setPersistSessionHandler( createPersistSessionHandler( account, @@ -309,6 +321,8 @@ export function Provider({children}: React.PropsWithChildren<{}>) { ) __globalAgent = agent + // @ts-ignore + if (IS_DEV && isWeb) window.agent = agent queryClient.clear() upsertAccount(account) @@ -348,6 +362,9 @@ export function Provider({children}: React.PropsWithChildren<{}>) { {networkErrorCallback: clearCurrentAccount}, ), }) + // @ts-ignore + if (IS_DEV && isWeb) window.agent = agent + await configureModeration(agent, account) let canReusePrevSession = false try { @@ -643,6 +660,28 @@ export function Provider({children}: React.PropsWithChildren<{}>) { ) } +async function configureModeration(agent: BskyAgent, account: SessionAccount) { + if (IS_TEST_USER(account.handle)) { + const did = ( + await agent + .resolveHandle({handle: 'mod-authority.test'}) + .catch(_ => undefined) + )?.data.did + if (did) { + console.warn('USING TEST ENV MODERATION') + BskyAgent.configure({appLabelers: [did]}) + } + } else { + BskyAgent.configure({appLabelers: [BSKY_LABELER_DID]}) + const labelerDids = await readLabelers(account.did).catch(_ => {}) + if (labelerDids) { + agent.configureLabelersHeader( + labelerDids.filter(did => did !== BSKY_LABELER_DID), + ) + } + } +} + export function useSession() { return React.useContext(StateContext) } diff --git a/src/state/shell/composer.tsx b/src/state/shell/composer.tsx index c9dbfbeac..5b4e50543 100644 --- a/src/state/shell/composer.tsx +++ b/src/state/shell/composer.tsx @@ -2,7 +2,8 @@ import React from 'react' import { AppBskyEmbedRecord, AppBskyRichtextFacet, - PostModeration, + ModerationDecision, + AppBskyActorDefs, } from '@atproto/api' import {useNonReactiveCallback} from '#/lib/hooks/useNonReactiveCallback' @@ -10,13 +11,9 @@ export interface ComposerOptsPostRef { uri: string cid: string text: string - author: { - handle: string - displayName?: string - avatar?: string - } + author: AppBskyActorDefs.ProfileViewBasic embed?: AppBskyEmbedRecord.ViewRecord['embed'] - moderation?: PostModeration + moderation?: ModerationDecision } export interface ComposerOptsQuote { uri: string diff --git a/src/view/com/auth/HomeLoggedOutCTA.tsx b/src/view/com/auth/HomeLoggedOutCTA.tsx index f796d8bae..a5b5bf7ba 100644 --- a/src/view/com/auth/HomeLoggedOutCTA.tsx +++ b/src/view/com/auth/HomeLoggedOutCTA.tsx @@ -52,7 +52,9 @@ export function HomeLoggedOutCTA() { onPress={showCreateAccount} accessibilityRole="button" accessibilityLabel={_(msg`Create new account`)} - accessibilityHint="Opens flow to create a new Bluesky account"> + accessibilityHint={_( + msg`Opens flow to create a new Bluesky account`, + )}> <Text style={[ s.white, @@ -68,7 +70,9 @@ export function HomeLoggedOutCTA() { onPress={showSignIn} accessibilityRole="button" accessibilityLabel={_(msg`Sign in`)} - accessibilityHint="Opens flow to sign into your existing Bluesky account"> + accessibilityHint={_( + msg`Opens flow to sign into your existing Bluesky account`, + )}> <Text style={[ pal.text, diff --git a/src/view/com/auth/SplashScreen.tsx b/src/view/com/auth/SplashScreen.tsx index 134ae11f1..f3d783476 100644 --- a/src/view/com/auth/SplashScreen.tsx +++ b/src/view/com/auth/SplashScreen.tsx @@ -66,7 +66,9 @@ export const SplashScreen = ({ onPress={onPressCreateAccount} accessibilityRole="button" accessibilityLabel={_(msg`Create new account`)} - accessibilityHint="Opens flow to create a new Bluesky account"> + accessibilityHint={_( + msg`Opens flow to create a new Bluesky account`, + )}> <Text style={[s.white, styles.btnLabel]}> <Trans>Create a new account</Trans> </Text> @@ -77,7 +79,9 @@ export const SplashScreen = ({ onPress={onPressSignin} accessibilityRole="button" accessibilityLabel={_(msg`Sign in`)} - accessibilityHint="Opens flow to sign into your existing Bluesky account"> + accessibilityHint={_( + msg`Opens flow to sign into your existing Bluesky account`, + )}> <Text style={[pal.text, styles.btnLabel]}> <Trans>Sign In</Trans> </Text> diff --git a/src/view/com/auth/create/Policies.tsx b/src/view/com/auth/create/Policies.tsx index 2c7d60818..803e2ad32 100644 --- a/src/view/com/auth/create/Policies.tsx +++ b/src/view/com/auth/create/Policies.tsx @@ -9,6 +9,8 @@ import {TextLink} from '../../util/Link' import {Text} from '../../util/text/Text' import {s, colors} from 'lib/styles' import {usePalette} from 'lib/hooks/usePalette' +import {Trans, msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' type ServiceDescription = ComAtprotoServerDescribeServer.OutputSchema @@ -20,6 +22,7 @@ export const Policies = ({ needsGuardian: boolean }) => { const pal = usePalette('default') + const {_} = useLingui() if (!serviceDescription) { return <View /> } @@ -40,7 +43,9 @@ export const Policies = ({ /> </View> <Text style={[pal.textLight, s.pl5, s.flex1]}> - This service has not provided terms of service or a privacy policy. + <Trans> + This service has not provided terms of service or a privacy policy. + </Trans> </Text> </View> ) @@ -51,7 +56,7 @@ export const Policies = ({ <TextLink key="tos" href={tos} - text="Terms of Service" + text={_(msg`Terms of Service`)} style={[pal.link, s.underline]} />, ) @@ -61,7 +66,7 @@ export const Policies = ({ <TextLink key="pp" href={pp} - text="Privacy Policy" + text={_(msg`Privacy Policy`)} style={[pal.link, s.underline]} />, ) @@ -79,12 +84,14 @@ export const Policies = ({ return ( <View style={styles.policies}> <Text style={pal.textLight}> - By creating an account you agree to the {els}. + <Trans>By creating an account you agree to the {els}.</Trans> </Text> {needsGuardian && ( <Text style={[pal.textLight, s.bold]}> - If you are not yet an adult according to the laws of your country, - your parent or legal guardian must read these Terms on your behalf. + <Trans> + If you are not yet an adult according to the laws of your country, + your parent or legal guardian must read these Terms on your behalf. + </Trans> </Text> )} </View> diff --git a/src/view/com/auth/create/state.ts b/src/view/com/auth/create/state.ts index 7a727ec0b..840084dcb 100644 --- a/src/view/com/auth/create/state.ts +++ b/src/view/com/auth/create/state.ts @@ -12,7 +12,7 @@ import {createFullHandle, validateHandle} from '#/lib/strings/handles' import {cleanError} from '#/lib/strings/errors' import {useOnboardingDispatch} from '#/state/shell/onboarding' import {useSessionApi} from '#/state/session' -import {DEFAULT_SERVICE, IS_PROD_SERVICE} from '#/lib/constants' +import {DEFAULT_SERVICE, IS_TEST_USER} from '#/lib/constants' import { DEFAULT_PROD_FEEDS, usePreferencesSetBirthDateMutation, @@ -147,7 +147,7 @@ export function useSubmitCreateAccount( : undefined, }) setBirthDate({birthDate: uiState.birthDate}) - if (IS_PROD_SERVICE(uiState.serviceUrl)) { + if (!IS_TEST_USER(uiState.handle)) { setSavedFeeds(DEFAULT_PROD_FEEDS) } } catch (e: any) { diff --git a/src/view/com/auth/login/ChooseAccountForm.tsx b/src/view/com/auth/login/ChooseAccountForm.tsx index 32cd8315d..d3b075fdb 100644 --- a/src/view/com/auth/login/ChooseAccountForm.tsx +++ b/src/view/com/auth/login/ChooseAccountForm.tsx @@ -45,7 +45,11 @@ function AccountItem({ accessibilityHint={_(msg`Double tap to sign in`)}> <View style={[pal.borderDark, styles.groupContent, styles.noTopBorder]}> <View style={s.p10}> - <UserAvatar avatar={profile?.avatar} size={30} /> + <UserAvatar + avatar={profile?.avatar} + size={30} + type={profile?.associated?.labeler ? 'labeler' : 'user'} + /> </View> <Text style={styles.accountText}> <Text type="lg-bold" style={pal.text}> diff --git a/src/view/com/auth/login/LoginForm.tsx b/src/view/com/auth/login/LoginForm.tsx index fdba9f203..3202d69c5 100644 --- a/src/view/com/auth/login/LoginForm.tsx +++ b/src/view/com/auth/login/LoginForm.tsx @@ -207,7 +207,7 @@ export const LoginForm = ({ testID="loginPasswordInput" ref={passwordInputRef} style={[pal.text, styles.textInput]} - placeholder="Password" + placeholder={_(msg`Password`)} placeholderTextColor={pal.colors.textLight} autoCapitalize="none" autoCorrect={false} diff --git a/src/view/com/auth/onboarding/RecommendedFollowsItem.tsx b/src/view/com/auth/onboarding/RecommendedFollowsItem.tsx index 07001068c..dba3f8c56 100644 --- a/src/view/com/auth/onboarding/RecommendedFollowsItem.tsx +++ b/src/view/com/auth/onboarding/RecommendedFollowsItem.tsx @@ -1,6 +1,6 @@ import React from 'react' import {View, StyleSheet, ActivityIndicator} from 'react-native' -import {ProfileModeration, AppBskyActorDefs} from '@atproto/api' +import {ModerationDecision, AppBskyActorDefs} from '@atproto/api' import {Button} from '#/view/com/util/forms/Button' import {usePalette} from 'lib/hooks/usePalette' import {sanitizeDisplayName} from 'lib/strings/display-names' @@ -11,14 +11,15 @@ import {Text} from 'view/com/util/text/Text' import Animated, {FadeInRight} from 'react-native-reanimated' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {useAnalytics} from 'lib/analytics/analytics' -import {Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {Trans, msg} from '@lingui/macro' import {Shadow, useProfileShadow} from '#/state/cache/profile-shadow' import {useProfileFollowMutationQueue} from '#/state/queries/profile' import {logger} from '#/logger' type Props = { profile: AppBskyActorDefs.ProfileViewBasic - moderation: ProfileModeration + moderation: ModerationDecision onFollowStateChange: (props: { did: string following: boolean @@ -56,13 +57,13 @@ export function RecommendedFollowsItem({ ) } -export function ProfileCard({ +function ProfileCard({ profile, onFollowStateChange, moderation, }: { profile: Shadow<AppBskyActorDefs.ProfileViewBasic> - moderation: ProfileModeration + moderation: ModerationDecision onFollowStateChange: (props: { did: string following: boolean @@ -70,9 +71,13 @@ export function ProfileCard({ }) { const {track} = useAnalytics() const pal = usePalette('default') + const {_} = useLingui() const [addingMoreSuggestions, setAddingMoreSuggestions] = React.useState(false) - const [queueFollow, queueUnfollow] = useProfileFollowMutationQueue(profile) + const [queueFollow, queueUnfollow] = useProfileFollowMutationQueue( + profile, + 'RecommendedFollowsItem', + ) const onToggleFollow = React.useCallback(async () => { try { @@ -110,7 +115,7 @@ export function ProfileCard({ <UserAvatar size={40} avatar={profile.avatar} - moderation={moderation.avatar} + moderation={moderation.ui('avatar')} /> </View> <View style={styles.layoutContent}> @@ -121,7 +126,7 @@ export function ProfileCard({ lineHeight={1.2}> {sanitizeDisplayName( profile.displayName || sanitizeHandle(profile.handle), - moderation.profile, + moderation.ui('displayName'), )} </Text> <Text type="xl" style={[pal.textLight]} numberOfLines={1}> @@ -133,7 +138,7 @@ export function ProfileCard({ type={profile.viewer?.following ? 'default' : 'inverted'} labelStyle={styles.followButton} onPress={onToggleFollow} - label={profile.viewer?.following ? 'Unfollow' : 'Follow'} + label={profile.viewer?.following ? _(msg`Unfollow`) : _(msg`Follow`)} /> </View> {profile.description ? ( diff --git a/src/view/com/auth/onboarding/WelcomeMobile.tsx b/src/view/com/auth/onboarding/WelcomeMobile.tsx index 5de1a7817..b8659d56c 100644 --- a/src/view/com/auth/onboarding/WelcomeMobile.tsx +++ b/src/view/com/auth/onboarding/WelcomeMobile.tsx @@ -6,7 +6,8 @@ import {usePalette} from 'lib/hooks/usePalette' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {Button} from 'view/com/util/forms/Button' import {ViewHeader} from 'view/com/util/ViewHeader' -import {Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {Trans, msg} from '@lingui/macro' type Props = { next: () => void @@ -15,6 +16,7 @@ type Props = { export function WelcomeMobile({next, skip}: Props) { const pal = usePalette('default') + const {_} = useLingui() return ( <View style={[styles.container]} testID="welcomeOnboarding"> @@ -91,7 +93,7 @@ export function WelcomeMobile({next, skip}: Props) { <Button onPress={next} - label="Continue" + label={_(msg`Continue`)} testID="continueBtn" style={[styles.buttonContainer]} labelStyle={styles.buttonText} diff --git a/src/view/com/auth/server-input/index.tsx b/src/view/com/auth/server-input/index.tsx index 32b5a3141..b26ac1dcb 100644 --- a/src/view/com/auth/server-input/index.tsx +++ b/src/view/com/auth/server-input/index.tsx @@ -115,7 +115,7 @@ export function ServerInputDialog({ testID="customServerTextInput" value={customAddress} onChangeText={setCustomAddress} - label={_(msg`my-server.com`)} + label="my-server.com" accessibilityLabelledBy="address-input-label" autoCapitalize="none" keyboardType="url" diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx index 2855d4232..ab7551b60 100644 --- a/src/view/com/composer/Composer.tsx +++ b/src/view/com/composer/Composer.tsx @@ -39,7 +39,7 @@ import {usePalette} from 'lib/hooks/usePalette' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {useExternalLinkFetch} from './useExternalLinkFetch' import {isWeb, isNative, isAndroid, isIOS} from 'platform/detection' -import QuoteEmbed from '../util/post-embeds/QuoteEmbed' +import {QuoteEmbed} from '../util/post-embeds/QuoteEmbed' import {GalleryModel} from 'state/models/media/gallery' import {Gallery} from './photos/Gallery' import {MAX_GRAPHEME_LENGTH} from 'lib/constants' @@ -49,7 +49,7 @@ import {SuggestedLanguage} from './select-language/SuggestedLanguage' import {insertMentionAt} from 'lib/strings/mention-manip' import {Trans, msg} from '@lingui/macro' import {useLingui} from '@lingui/react' -import {useModals, useModalControls} from '#/state/modals' +import {useModals} from '#/state/modals' import {useRequireAltTextEnabled} from '#/state/preferences' import { useLanguagePrefs, @@ -63,6 +63,9 @@ import {emitPostCreated} from '#/state/events' import {ThreadgateSetting} from '#/state/queries/threadgate' import {logger} from '#/logger' import {ComposerReplyTo} from 'view/com/composer/ComposerReplyTo' +import * as Prompt from '#/components/Prompt' +import {useDialogStateControlContext} from 'state/dialogs' +import {logEvent} from '#/lib/statsig/statsig' type Props = ComposerOpts export const ComposePost = observer(function ComposePost({ @@ -76,8 +79,7 @@ export const ComposePost = observer(function ComposePost({ }: Props) { const {currentAccount} = useSession() const {data: currentProfile} = useProfileQuery({did: currentAccount!.did}) - const {isModalActive, activeModals} = useModals() - const {openModal, closeModal} = useModalControls() + const {isModalActive} = useModals() const {closeComposer} = useComposerControls() const {track} = useAnalytics() const pal = usePalette('default') @@ -87,6 +89,9 @@ export const ComposePost = observer(function ComposePost({ const langPrefs = useLanguagePrefs() const setLangPrefs = useLanguagePrefsApi() const textInput = useRef<TextInputRef>(null) + const discardPromptControl = Prompt.usePromptControl() + const {closeAllDialogs} = useDialogStateControlContext() + const [isKeyboardVisible] = useIsKeyboardVisible({iosUseWillEvents: true}) const [isProcessing, setIsProcessing] = useState(false) const [processingState, setProcessingState] = useState('') @@ -134,27 +139,21 @@ export const ComposePost = observer(function ComposePost({ const onPressCancel = useCallback(() => { if (graphemeLength > 0 || !gallery.isEmpty) { - if (activeModals.some(modal => modal.name === 'confirm')) { - closeModal() - } + closeAllDialogs() if (Keyboard) { Keyboard.dismiss() } - openModal({ - name: 'confirm', - title: _(msg`Discard draft`), - onPressConfirm: onClose, - onPressCancel: () => { - closeModal() - }, - message: _(msg`Are you sure you'd like to discard this draft?`), - confirmBtnText: _(msg`Discard`), - confirmBtnStyle: {backgroundColor: colors.red4}, - }) + discardPromptControl.open() } else { onClose() } - }, [openModal, closeModal, activeModals, onClose, graphemeLength, gallery, _]) + }, [ + graphemeLength, + gallery.isEmpty, + closeAllDialogs, + discardPromptControl, + onClose, + ]) // android back button useEffect(() => { if (!isAndroid) { @@ -257,6 +256,16 @@ export const ComposePost = observer(function ComposePost({ setIsProcessing(false) return } finally { + if (postUri) { + logEvent('post:create', { + imageCount: gallery.size, + isReply: replyTo != null, + hasLink: extLink != null, + hasQuote: quote != null, + langs: langPrefs.postLanguage, + logContext: 'Composer', + }) + } track('Create Post', { imageCount: gallery.size, }) @@ -406,7 +415,11 @@ export const ComposePost = observer(function ComposePost({ styles.textInputLayout, isNative && styles.textInputLayoutMobile, ]}> - <UserAvatar avatar={currentProfile?.avatar} size={50} /> + <UserAvatar + avatar={currentProfile?.avatar} + size={50} + type={currentProfile?.associated?.labeler ? 'labeler' : 'user'} + /> <TextInput ref={textInput} richtext={richtext} @@ -488,6 +501,15 @@ export const ComposePost = observer(function ComposePost({ <CharProgress count={graphemeLength} /> </View> </View> + + <Prompt.Basic + control={discardPromptControl} + title={_(msg`Discard draft?`)} + description={_(msg`Are you sure you'd like to discard this draft?`)} + onConfirm={onClose} + confirmButtonCta={_(msg`Discard`)} + confirmButtonColor="negative" + /> </KeyboardAvoidingView> ) }) diff --git a/src/view/com/composer/ComposerReplyTo.tsx b/src/view/com/composer/ComposerReplyTo.tsx index 39a1473a3..0c1b87d04 100644 --- a/src/view/com/composer/ComposerReplyTo.tsx +++ b/src/view/com/composer/ComposerReplyTo.tsx @@ -15,7 +15,7 @@ import {sanitizeDisplayName} from 'lib/strings/display-names' import {sanitizeHandle} from 'lib/strings/handles' import {UserAvatar} from 'view/com/util/UserAvatar' import {Text} from 'view/com/util/text/Text' -import QuoteEmbed from 'view/com/util/post-embeds/QuoteEmbed' +import {QuoteEmbed} from 'view/com/util/post-embeds/QuoteEmbed' export function ComposerReplyTo({replyTo}: {replyTo: ComposerOptsPostRef}) { const pal = usePalette('default') @@ -86,7 +86,8 @@ export function ComposerReplyTo({replyTo}: {replyTo: ComposerOptsPostRef}) { <UserAvatar avatar={replyTo.author.avatar} size={50} - moderation={replyTo.moderation?.avatar} + moderation={replyTo.moderation?.ui('avatar')} + type={replyTo.author.associated?.labeler ? 'labeler' : 'user'} /> <View style={styles.replyToPost}> <Text type="xl-medium" style={[pal.text]}> @@ -103,7 +104,7 @@ export function ComposerReplyTo({replyTo}: {replyTo: ComposerOptsPostRef}) { {replyTo.text} </Text> </View> - {images && !replyTo.moderation?.embed.blur && ( + {images && !replyTo.moderation?.ui('contentMedia').blur && ( <ComposerReplyToImages images={images} showFull={showFull} /> )} </View> diff --git a/src/view/com/composer/Prompt.tsx b/src/view/com/composer/Prompt.tsx index 632bb2634..16d1b6fb9 100644 --- a/src/view/com/composer/Prompt.tsx +++ b/src/view/com/composer/Prompt.tsx @@ -23,7 +23,11 @@ export function ComposePrompt({onPressCompose}: {onPressCompose: () => void}) { accessibilityRole="button" accessibilityLabel={_(msg`Compose reply`)} accessibilityHint={_(msg`Opens composer`)}> - <UserAvatar avatar={profile?.avatar} size={38} /> + <UserAvatar + avatar={profile?.avatar} + size={38} + type={profile?.associated?.labeler ? 'labeler' : 'user'} + /> <Text type="xl" style={[ diff --git a/src/view/com/composer/photos/OpenCameraBtn.tsx b/src/view/com/composer/photos/OpenCameraBtn.tsx index a288e7310..4353704d5 100644 --- a/src/view/com/composer/photos/OpenCameraBtn.tsx +++ b/src/view/com/composer/photos/OpenCameraBtn.tsx @@ -1,5 +1,6 @@ import React, {useCallback} from 'react' import {TouchableOpacity, StyleSheet} from 'react-native' +import * as MediaLibrary from 'expo-media-library' import { FontAwesomeIcon, FontAwesomeIconStyle, @@ -24,6 +25,8 @@ export function OpenCameraBtn({gallery}: Props) { const {track} = useAnalytics() const {_} = useLingui() const {requestCameraAccessIfNeeded} = useCameraPermission() + const [mediaPermissionRes, requestMediaPermission] = + MediaLibrary.usePermissions() const onPressTakePicture = useCallback(async () => { track('Composer:CameraOpened') @@ -31,6 +34,9 @@ export function OpenCameraBtn({gallery}: Props) { if (!(await requestCameraAccessIfNeeded())) { return } + if (!mediaPermissionRes?.granted && mediaPermissionRes?.canAskAgain) { + await requestMediaPermission() + } const img = await openCamera({ width: POST_IMG_MAX.width, @@ -38,12 +44,23 @@ export function OpenCameraBtn({gallery}: Props) { freeStyleCropEnabled: true, }) + // If we don't have permissions it's fine, we just wont save it. The post itself will still have access to + // the image even without these permissions + if (mediaPermissionRes) { + await MediaLibrary.createAssetAsync(img.path) + } gallery.add(img) } catch (err: any) { // ignore logger.warn('Error using camera', {error: err}) } - }, [gallery, track, requestCameraAccessIfNeeded]) + }, [ + gallery, + track, + requestCameraAccessIfNeeded, + mediaPermissionRes, + requestMediaPermission, + ]) const shouldShowCameraButton = isNative || isMobileWeb if (!shouldShowCameraButton) { diff --git a/src/view/com/composer/select-language/SelectLangBtn.tsx b/src/view/com/composer/select-language/SelectLangBtn.tsx index 78b1e9ba2..785622225 100644 --- a/src/view/com/composer/select-language/SelectLangBtn.tsx +++ b/src/view/com/composer/select-language/SelectLangBtn.tsx @@ -20,7 +20,7 @@ import { toPostLanguages, hasPostLanguage, } from '#/state/preferences/languages' -import {t, msg} from '@lingui/macro' +import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' export function SelectLangBtn() { @@ -84,15 +84,15 @@ export function SelectLangBtn() { } return [ - {heading: true, label: t`Post language`}, + {heading: true, label: _(msg`Post language`)}, ...arr.slice(0, 6), {sep: true}, { - label: t`Other...`, + label: _(msg`Other...`), onPress: onPressMore, }, ] - }, [onPressMore, langPrefs, setLangPrefs, postLanguagesPref]) + }, [onPressMore, langPrefs, setLangPrefs, postLanguagesPref, _]) return ( <DropdownButton diff --git a/src/view/com/composer/text-input/mobile/Autocomplete.tsx b/src/view/com/composer/text-input/mobile/Autocomplete.tsx index c400aa48d..9c8f8f916 100644 --- a/src/view/com/composer/text-input/mobile/Autocomplete.tsx +++ b/src/view/com/composer/text-input/mobile/Autocomplete.tsx @@ -78,7 +78,11 @@ export function Autocomplete({ accessibilityLabel={`Select ${item.handle}`} accessibilityHint=""> <View style={styles.avatarAndHandle}> - <UserAvatar avatar={item.avatar ?? null} size={24} /> + <UserAvatar + avatar={item.avatar ?? null} + size={24} + type={item.associated?.labeler ? 'labeler' : 'user'} + /> <Text type="md-medium" style={pal.text}> {displayName} </Text> diff --git a/src/view/com/composer/text-input/web/Autocomplete.tsx b/src/view/com/composer/text-input/web/Autocomplete.tsx index 76058fed3..29b8f0bc6 100644 --- a/src/view/com/composer/text-input/web/Autocomplete.tsx +++ b/src/view/com/composer/text-input/web/Autocomplete.tsx @@ -175,7 +175,11 @@ const MentionList = forwardRef<MentionListRef, SuggestionProps>( }} accessibilityRole="button"> <View style={styles.avatarAndDisplayName}> - <UserAvatar avatar={item.avatar ?? null} size={26} /> + <UserAvatar + avatar={item.avatar ?? null} + size={26} + type={item.associated?.labeler ? 'labeler' : 'user'} + /> <Text style={pal.text} numberOfLines={1}> {displayName} </Text> diff --git a/src/view/com/feeds/FeedSourceCard.tsx b/src/view/com/feeds/FeedSourceCard.tsx index 9bd7238df..9300b4159 100644 --- a/src/view/com/feeds/FeedSourceCard.tsx +++ b/src/view/com/feeds/FeedSourceCard.tsx @@ -6,14 +6,11 @@ import {RichText} from '#/components/RichText' import {usePalette} from 'lib/hooks/usePalette' import {s} from 'lib/styles' import {UserAvatar} from '../util/UserAvatar' -import {useNavigation} from '@react-navigation/native' -import {NavigationProp} from 'lib/routes/types' import {pluralize} from 'lib/strings/helpers' import {AtUri} from '@atproto/api' import * as Toast from 'view/com/util/Toast' import {sanitizeHandle} from 'lib/strings/handles' import {logger} from '#/logger' -import {useModalControls} from '#/state/modals' import {Trans, msg} from '@lingui/macro' import {useLingui} from '@lingui/react' import { @@ -26,6 +23,8 @@ import { import {useFeedSourceInfoQuery, FeedSourceInfo} from '#/state/queries/feed' import {FeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' import {useTheme} from '#/alf' +import * as Prompt from '#/components/Prompt' +import {useNavigationDeduped} from 'lib/hooks/useNavigationDeduped' export function FeedSourceCard({ feedUri, @@ -86,8 +85,8 @@ export function FeedSourceCardLoaded({ const t = useTheme() const pal = usePalette('default') const {_} = useLingui() - const navigation = useNavigation<NavigationProp>() - const {openModal} = useModalControls() + const removePromptControl = Prompt.usePromptControl() + const navigation = useNavigationDeduped() const {isPending: isSavePending, mutateAsync: saveFeed} = useSaveFeedMutation() @@ -97,40 +96,45 @@ export function FeedSourceCardLoaded({ const isSaved = Boolean(preferences?.feeds?.saved?.includes(feed?.uri || '')) + const onSave = React.useCallback(async () => { + if (!feed) return + + try { + if (pinOnSave) { + await pinFeed({uri: feed.uri}) + } else { + await saveFeed({uri: feed.uri}) + } + Toast.show(_(msg`Added to my feeds`)) + } catch (e) { + Toast.show(_(msg`There was an issue contacting your server`)) + logger.error('Failed to save feed', {message: e}) + } + }, [_, feed, pinFeed, pinOnSave, saveFeed]) + + const onUnsave = React.useCallback(async () => { + if (!feed) return + + try { + await removeFeed({uri: feed.uri}) + // await item.unsave() + Toast.show(_(msg`Removed from my feeds`)) + } catch (e) { + Toast.show(_(msg`There was an issue contacting your server`)) + logger.error('Failed to unsave feed', {message: e}) + } + }, [_, feed, removeFeed]) + const onToggleSaved = React.useCallback(async () => { // Only feeds can be un/saved, lists are handled elsewhere if (feed?.type !== 'feed') return if (isSaved) { - openModal({ - name: 'confirm', - title: _(msg`Remove from my feeds`), - message: _(msg`Remove ${feed?.displayName} from my feeds?`), - onPressConfirm: async () => { - try { - await removeFeed({uri: feed.uri}) - // await item.unsave() - Toast.show(_(msg`Removed from my feeds`)) - } catch (e) { - Toast.show(_(msg`There was an issue contacting your server`)) - logger.error('Failed to unsave feed', {message: e}) - } - }, - }) + removePromptControl.open() } else { - try { - if (pinOnSave) { - await pinFeed({uri: feed.uri}) - } else { - await saveFeed({uri: feed.uri}) - } - Toast.show(_(msg`Added to my feeds`)) - } catch (e) { - Toast.show(_(msg`There was an issue contacting your server`)) - logger.error('Failed to save feed', {message: e}) - } + await onSave() } - }, [isSaved, openModal, feed, removeFeed, saveFeed, _, pinOnSave, pinFeed]) + }, [feed?.type, isSaved, removePromptControl, onSave]) /* * LOAD STATE @@ -168,25 +172,7 @@ export function FeedSourceCardLoaded({ accessibilityRole="button" accessibilityLabel={_(msg`Remove from my feeds`)} accessibilityHint="" - onPress={() => { - openModal({ - name: 'confirm', - title: _(msg`Remove from my feeds`), - message: _(msg`Remove this feed from my feeds?`), - onPressConfirm: async () => { - try { - await removeFeed({uri: feedUri}) - // await item.unsave() - Toast.show(_(msg`Removed from my feeds`)) - } catch (e) { - Toast.show( - _(msg`There was an issue contacting your server`), - ) - logger.error('Failed to unsave feed', {message: e}) - } - }, - }) - }} + onPress={onToggleSaved} hitSlop={15} style={styles.btn}> <FontAwesomeIcon @@ -200,89 +186,104 @@ export function FeedSourceCardLoaded({ ) return ( - <Pressable - testID={`feed-${feed.displayName}`} - accessibilityRole="button" - style={[styles.container, pal.border, style]} - onPress={() => { - if (feed.type === 'feed') { - navigation.push('ProfileFeed', { - name: feed.creatorDid, - rkey: new AtUri(feed.uri).rkey, - }) - } else if (feed.type === 'list') { - navigation.push('ProfileList', { - name: feed.creatorDid, - rkey: new AtUri(feed.uri).rkey, - }) - } - }} - key={feed.uri}> - <View style={[styles.headerContainer]}> - <View style={[s.mr10]}> - <UserAvatar type="algo" size={36} avatar={feed.avatar} /> - </View> - <View style={[styles.headerTextContainer]}> - <Text style={[pal.text, s.bold]} numberOfLines={3}> - {feed.displayName} - </Text> - <Text style={[pal.textLight]} numberOfLines={3}> - {feed.type === 'feed' ? ( - <Trans>Feed by {sanitizeHandle(feed.creatorHandle, '@')}</Trans> - ) : ( - <Trans>List by {sanitizeHandle(feed.creatorHandle, '@')}</Trans> - )} - </Text> - </View> - - {showSaveBtn && feed.type === 'feed' && ( - <View style={[s.justifyCenter]}> - <Pressable - testID={`feed-${feed.displayName}-toggleSave`} - disabled={isSavePending || isPinPending || isRemovePending} - accessibilityRole="button" - accessibilityLabel={ - isSaved ? _(msg`Remove from my feeds`) : _(msg`Add to my feeds`) - } - accessibilityHint="" - onPress={onToggleSaved} - hitSlop={15} - style={styles.btn}> - {isSaved ? ( - <FontAwesomeIcon - icon={['far', 'trash-can']} - size={19} - color={pal.colors.icon} - /> + <> + <Pressable + testID={`feed-${feed.displayName}`} + accessibilityRole="button" + style={[styles.container, pal.border, style]} + onPress={() => { + if (feed.type === 'feed') { + navigation.push('ProfileFeed', { + name: feed.creatorDid, + rkey: new AtUri(feed.uri).rkey, + }) + } else if (feed.type === 'list') { + navigation.push('ProfileList', { + name: feed.creatorDid, + rkey: new AtUri(feed.uri).rkey, + }) + } + }} + key={feed.uri}> + <View style={[styles.headerContainer]}> + <View style={[s.mr10]}> + <UserAvatar type="algo" size={36} avatar={feed.avatar} /> + </View> + <View style={[styles.headerTextContainer]}> + <Text style={[pal.text, s.bold]} numberOfLines={3}> + {feed.displayName} + </Text> + <Text style={[pal.textLight]} numberOfLines={3}> + {feed.type === 'feed' ? ( + <Trans>Feed by {sanitizeHandle(feed.creatorHandle, '@')}</Trans> ) : ( - <FontAwesomeIcon - icon="plus" - size={18} - color={pal.colors.link} - /> + <Trans>List by {sanitizeHandle(feed.creatorHandle, '@')}</Trans> )} - </Pressable> + </Text> </View> - )} - </View> - {showDescription && feed.description ? ( - <RichText - style={[t.atoms.text_contrast_high, styles.description]} - value={feed.description} - numberOfLines={3} - /> - ) : null} + {showSaveBtn && feed.type === 'feed' && ( + <View style={[s.justifyCenter]}> + <Pressable + testID={`feed-${feed.displayName}-toggleSave`} + disabled={isSavePending || isPinPending || isRemovePending} + accessibilityRole="button" + accessibilityLabel={ + isSaved + ? _(msg`Remove from my feeds`) + : _(msg`Add to my feeds`) + } + accessibilityHint="" + onPress={onToggleSaved} + hitSlop={15} + style={styles.btn}> + {isSaved ? ( + <FontAwesomeIcon + icon={['far', 'trash-can']} + size={19} + color={pal.colors.icon} + /> + ) : ( + <FontAwesomeIcon + icon="plus" + size={18} + color={pal.colors.link} + /> + )} + </Pressable> + </View> + )} + </View> + + {showDescription && feed.description ? ( + <RichText + style={[t.atoms.text_contrast_high, styles.description]} + value={feed.description} + numberOfLines={3} + /> + ) : null} - {showLikes && feed.type === 'feed' ? ( - <Text type="sm-medium" style={[pal.text, pal.textLight]}> - <Trans> - Liked by {feed.likeCount || 0}{' '} - {pluralize(feed.likeCount || 0, 'user')} - </Trans> - </Text> - ) : null} - </Pressable> + {showLikes && feed.type === 'feed' ? ( + <Text type="sm-medium" style={[pal.text, pal.textLight]}> + <Trans> + Liked by {feed.likeCount || 0}{' '} + {pluralize(feed.likeCount || 0, 'user')} + </Trans> + </Text> + ) : null} + </Pressable> + + <Prompt.Basic + control={removePromptControl} + title={_(msg`Remove from my feeds?`)} + description={_( + msg`Are you sure you want to remove ${feed.displayName} from your feeds?`, + )} + onConfirm={onUnsave} + confirmButtonCta={_(msg`Remove`)} + confirmButtonColor="negative" + /> + </> ) } diff --git a/src/view/com/lightbox/ImageViewing/components/ImageDefaultHeader.tsx b/src/view/com/lightbox/ImageViewing/components/ImageDefaultHeader.tsx index 3401adaff..3872919de 100644 --- a/src/view/com/lightbox/ImageViewing/components/ImageDefaultHeader.tsx +++ b/src/view/com/lightbox/ImageViewing/components/ImageDefaultHeader.tsx @@ -6,9 +6,11 @@ * */ import React from 'react' -import {createHitslop} from 'lib/constants' import {SafeAreaView, Text, TouchableOpacity, StyleSheet} from 'react-native' -import {t} from '@lingui/macro' +import {msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' + +import {createHitslop} from '#/lib/constants' type Props = { onRequestClose: () => void @@ -16,20 +18,23 @@ type Props = { const HIT_SLOP = createHitslop(16) -const ImageDefaultHeader = ({onRequestClose}: Props) => ( - <SafeAreaView style={styles.root}> - <TouchableOpacity - style={styles.closeButton} - onPress={onRequestClose} - hitSlop={HIT_SLOP} - accessibilityRole="button" - accessibilityLabel={t`Close image`} - accessibilityHint={t`Closes viewer for header image`} - onAccessibilityEscape={onRequestClose}> - <Text style={styles.closeText}>✕</Text> - </TouchableOpacity> - </SafeAreaView> -) +const ImageDefaultHeader = ({onRequestClose}: Props) => { + const {_} = useLingui() + return ( + <SafeAreaView style={styles.root}> + <TouchableOpacity + style={styles.closeButton} + onPress={onRequestClose} + hitSlop={HIT_SLOP} + accessibilityRole="button" + accessibilityLabel={_(msg`Close image`)} + accessibilityHint={_(msg`Closes viewer for header image`)} + onAccessibilityEscape={onRequestClose}> + <Text style={styles.closeText}>✕</Text> + </TouchableOpacity> + </SafeAreaView> + ) +} const styles = StyleSheet.create({ root: { diff --git a/src/view/com/lightbox/Lightbox.tsx b/src/view/com/lightbox/Lightbox.tsx index 2ee5b8d59..5bab643ca 100644 --- a/src/view/com/lightbox/Lightbox.tsx +++ b/src/view/com/lightbox/Lightbox.tsx @@ -78,9 +78,9 @@ function LightboxFooter({imageIndex}: {imageIndex: number}) { try { await saveImageToMediaLibrary({uri}) - Toast.show('Saved to your camera roll.') + Toast.show(_(msg`Saved to your camera roll.`)) } catch (e: any) { - Toast.show(`Failed to save image: ${String(e)}`) + Toast.show(_(msg`Failed to save image: ${String(e)}`)) } }, [permissionResponse, requestPermission, _], diff --git a/src/view/com/modals/AppealLabel.tsx b/src/view/com/modals/AppealLabel.tsx deleted file mode 100644 index b0aaaf625..000000000 --- a/src/view/com/modals/AppealLabel.tsx +++ /dev/null @@ -1,139 +0,0 @@ -import React, {useState} from 'react' -import {StyleSheet, TouchableOpacity, View} from 'react-native' -import {ComAtprotoModerationDefs} from '@atproto/api' -import {ScrollView, TextInput} from './util' -import {Text} from '../util/text/Text' -import {s, colors} from 'lib/styles' -import {usePalette} from 'lib/hooks/usePalette' -import {Trans, msg} from '@lingui/macro' -import {useLingui} from '@lingui/react' -import {useModalControls} from '#/state/modals' -import {CharProgress} from '../composer/char-progress/CharProgress' -import {getAgent} from '#/state/session' -import * as Toast from '../util/Toast' -import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' - -export const snapPoints = ['40%'] - -type ReportComponentProps = - | { - uri: string - cid: string - } - | { - did: string - } - -export function Component(props: ReportComponentProps) { - const pal = usePalette('default') - const [details, setDetails] = useState<string>('') - const {_} = useLingui() - const {closeModal} = useModalControls() - const {isMobile} = useWebMediaQueries() - const isAccountReport = 'did' in props - - const submit = async () => { - try { - const $type = !isAccountReport - ? 'com.atproto.repo.strongRef' - : 'com.atproto.admin.defs#repoRef' - await getAgent().createModerationReport({ - reasonType: ComAtprotoModerationDefs.REASONAPPEAL, - subject: { - $type, - ...props, - }, - reason: details, - }) - Toast.show(_(msg`We'll look into your appeal promptly.`)) - } finally { - closeModal() - } - } - - return ( - <View - style={[ - pal.view, - s.flex1, - isMobile ? {paddingHorizontal: 12} : undefined, - ]} - testID="appealLabelModal"> - <Text - type="2xl-bold" - style={[pal.text, s.textCenter, {paddingBottom: 8}]}> - <Trans>Appeal Content Warning</Trans> - </Text> - <ScrollView> - <View style={[pal.btn, styles.detailsInputContainer]}> - <TextInput - accessibilityLabel={_(msg`Text input field`)} - accessibilityHint={_( - msg`Please tell us why you think this content warning was incorrectly applied!`, - )} - placeholder={_( - msg`Please tell us why you think this content warning was incorrectly applied!`, - )} - placeholderTextColor={pal.textLight.color} - value={details} - onChangeText={setDetails} - autoFocus={true} - numberOfLines={3} - multiline={true} - textAlignVertical="top" - maxLength={300} - style={[styles.detailsInput, pal.text]} - /> - <View style={styles.detailsInputBottomBar}> - <View style={styles.charCounter}> - <CharProgress count={details?.length || 0} /> - </View> - </View> - </View> - <TouchableOpacity - testID="confirmBtn" - onPress={submit} - style={styles.btn} - accessibilityRole="button" - accessibilityLabel={_(msg`Confirm`)} - accessibilityHint=""> - <Text style={[s.white, s.bold, s.f18]}> - <Trans>Submit</Trans> - </Text> - </TouchableOpacity> - </ScrollView> - </View> - ) -} - -const styles = StyleSheet.create({ - detailsInputContainer: { - borderRadius: 8, - marginBottom: 8, - }, - detailsInput: { - paddingHorizontal: 12, - paddingTop: 12, - paddingBottom: 12, - borderRadius: 8, - minHeight: 100, - fontSize: 16, - }, - detailsInputBottomBar: { - alignSelf: 'flex-end', - }, - charCounter: { - flexDirection: 'row', - alignItems: 'center', - paddingRight: 10, - paddingBottom: 8, - }, - btn: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'center', - borderRadius: 32, - padding: 14, - backgroundColor: colors.blue3, - }, -}) diff --git a/src/view/com/modals/BirthDateSettings.tsx b/src/view/com/modals/BirthDateSettings.tsx deleted file mode 100644 index 1cab95989..000000000 --- a/src/view/com/modals/BirthDateSettings.tsx +++ /dev/null @@ -1,151 +0,0 @@ -import React, {useState} from 'react' -import { - ActivityIndicator, - StyleSheet, - TouchableOpacity, - View, -} from 'react-native' -import {Text} from '../util/text/Text' -import {DateInput} from '../util/forms/DateInput' -import {ErrorMessage} from '../util/error/ErrorMessage' -import {s, colors} from 'lib/styles' -import {usePalette} from 'lib/hooks/usePalette' -import {isWeb} from 'platform/detection' -import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' -import {cleanError} from 'lib/strings/errors' -import {Trans, msg} from '@lingui/macro' -import {useLingui} from '@lingui/react' -import {useModalControls} from '#/state/modals' -import { - usePreferencesQuery, - usePreferencesSetBirthDateMutation, - UsePreferencesQueryResponse, -} from '#/state/queries/preferences' -import {logger} from '#/logger' - -export const snapPoints = ['50%', '90%'] - -function Inner({preferences}: {preferences: UsePreferencesQueryResponse}) { - const pal = usePalette('default') - const {isMobile} = useWebMediaQueries() - const {_} = useLingui() - const { - isPending, - isError, - error, - mutateAsync: setBirthDate, - } = usePreferencesSetBirthDateMutation() - const [date, setDate] = useState(preferences.birthDate || new Date()) - const {closeModal} = useModalControls() - - const onSave = React.useCallback(async () => { - try { - await setBirthDate({birthDate: date}) - closeModal() - } catch (e) { - logger.error(`setBirthDate failed`, {message: e}) - } - }, [date, setBirthDate, closeModal]) - - return ( - <View - testID="birthDateSettingsModal" - style={[pal.view, styles.container, isMobile && {paddingHorizontal: 18}]}> - <View style={styles.titleSection}> - <Text type="title-lg" style={[pal.text, styles.title]}> - <Trans>My Birthday</Trans> - </Text> - </View> - - <Text type="lg" style={[pal.textLight, {marginBottom: 10}]}> - <Trans>This information is not shared with other users.</Trans> - </Text> - - <View> - <DateInput - handleAsUTC - testID="birthdayInput" - value={date} - onChange={setDate} - buttonType="default-light" - buttonStyle={[pal.border, styles.dateInputButton]} - buttonLabelType="lg" - accessibilityLabel={_(msg`Birthday`)} - accessibilityHint={_(msg`Enter your birth date`)} - accessibilityLabelledBy="birthDate" - /> - </View> - - {isError ? ( - <ErrorMessage message={cleanError(error)} style={styles.error} /> - ) : undefined} - - <View style={[styles.btnContainer, pal.borderDark]}> - {isPending ? ( - <View style={styles.btn}> - <ActivityIndicator color="#fff" /> - </View> - ) : ( - <TouchableOpacity - testID="confirmBtn" - onPress={onSave} - style={styles.btn} - accessibilityRole="button" - accessibilityLabel={_(msg`Save`)} - accessibilityHint=""> - <Text style={[s.white, s.bold, s.f18]}> - <Trans>Save</Trans> - </Text> - </TouchableOpacity> - )} - </View> - </View> - ) -} - -export function Component({}: {}) { - const {data: preferences} = usePreferencesQuery() - - return !preferences ? ( - <ActivityIndicator /> - ) : ( - <Inner preferences={preferences} /> - ) -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - paddingBottom: isWeb ? 0 : 40, - }, - titleSection: { - paddingTop: isWeb ? 0 : 4, - paddingBottom: isWeb ? 14 : 10, - }, - title: { - textAlign: 'center', - fontWeight: '600', - marginBottom: 5, - }, - error: { - borderRadius: 6, - marginTop: 10, - }, - dateInputButton: { - borderWidth: 1, - borderRadius: 6, - paddingVertical: 14, - }, - btn: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'center', - borderRadius: 32, - padding: 14, - backgroundColor: colors.blue3, - }, - btnContainer: { - paddingTop: 20, - paddingHorizontal: 20, - }, -}) diff --git a/src/view/com/modals/ChangeHandle.tsx b/src/view/com/modals/ChangeHandle.tsx index a43c30c29..f04bdb0e4 100644 --- a/src/view/com/modals/ChangeHandle.tsx +++ b/src/view/com/modals/ChangeHandle.tsx @@ -150,7 +150,7 @@ export function Inner({ accessibilityHint={_(msg`Exits handle change process`)} onAccessibilityEscape={onPressCancel}> <Text type="lg" style={pal.textLight}> - Cancel + <Trans>Cancel</Trans> </Text> </TouchableOpacity> </View> @@ -254,7 +254,7 @@ function ProvidedHandleForm({ <TextInput testID="setHandleInput" style={[pal.text, styles.textInput]} - placeholder="e.g. alice" + placeholder={_(msg`e.g. alice`)} placeholderTextColor={pal.colors.textLight} autoCapitalize="none" keyboardAppearance={theme.colorScheme} @@ -277,8 +277,8 @@ function ProvidedHandleForm({ <TouchableOpacity onPress={onToggleCustom} accessibilityRole="button" - accessibilityHint="Hosting provider" - accessibilityLabel={_(msg`Opens modal for using custom domain`)}> + accessibilityLabel={_(msg`Hosting provider`)} + accessibilityHint={_(msg`Opens modal for using custom domain`)}> <Text type="md-medium" style={[pal.link, s.pl10, s.pt5]}> <Trans>I have my own domain</Trans> </Text> @@ -324,8 +324,8 @@ function CustomHandleForm({ Clipboard.setString( isDNSForm ? `did=${currentAccount.did}` : currentAccount.did, ) - Toast.show('Copied to clipboard') - }, [currentAccount, isDNSForm]) + Toast.show(_(msg`Copied to clipboard`)) + }, [currentAccount, isDNSForm, _]) const onChangeHandle = React.useCallback( (v: string) => { setHandle(v) @@ -378,7 +378,7 @@ function CustomHandleForm({ <TextInput testID="setHandleInput" style={[pal.text, styles.textInput]} - placeholder="e.g. alice.com" + placeholder={_(msg`e.g. alice.com`)} placeholderTextColor={pal.colors.textLight} autoCapitalize="none" keyboardAppearance={theme.colorScheme} @@ -387,7 +387,7 @@ function CustomHandleForm({ editable={!isProcessing} accessibilityLabelledBy="customDomain" accessibilityLabel={_(msg`Custom domain`)} - accessibilityHint="Input your preferred hosting provider" + accessibilityHint={_(msg`Input your preferred hosting provider`)} /> </View> <View style={styles.spacer} /> @@ -395,18 +395,18 @@ function CustomHandleForm({ <View style={[styles.selectableBtns]}> <SelectableBtn selected={isDNSForm} - label="DNS Panel" + label={_(msg`DNS Panel`)} left onSelect={() => setDNSForm(true)} - accessibilityHint="Use the DNS panel" + accessibilityHint={_(msg`Use the DNS panel`)} style={s.flex1} /> <SelectableBtn selected={!isDNSForm} - label="No DNS Panel" + label={_(msg`No DNS Panel`)} right onSelect={() => setDNSForm(false)} - accessibilityHint="Use a file on your server" + accessibilityHint={_(msg`Use a file on your server`)} style={s.flex1} /> </View> @@ -418,7 +418,7 @@ function CustomHandleForm({ </Text> <View style={[styles.dnsTable, pal.btn]}> <Text type="md-medium" style={[styles.dnsLabel, pal.text]}> - Host: + <Trans>Host:</Trans> </Text> <View style={[styles.dnsValue]}> <Text type="mono" style={[styles.monoText, pal.text]}> @@ -426,7 +426,7 @@ function CustomHandleForm({ </Text> </View> <Text type="md-medium" style={[styles.dnsLabel, pal.text]}> - Type: + <Trans>Type:</Trans> </Text> <View style={[styles.dnsValue]}> <Text type="mono" style={[styles.monoText, pal.text]}> @@ -434,7 +434,7 @@ function CustomHandleForm({ </Text> </View> <Text type="md-medium" style={[styles.dnsLabel, pal.text]}> - Value: + <Trans>Value:</Trans> </Text> <View style={[styles.dnsValue]}> <Text type="mono" style={[styles.monoText, pal.text]}> @@ -443,7 +443,7 @@ function CustomHandleForm({ </View> </View> <Text type="md" style={[pal.text, s.pt20, s.pl5]}> - This should create a domain record at:{' '} + <Trans>This should create a domain record at:</Trans> </Text> <Text type="mono" style={[styles.monoText, pal.text, s.pt5, s.pl5]}> _atproto.{handle} @@ -463,7 +463,7 @@ function CustomHandleForm({ </View> <View style={styles.spacer} /> <Text type="md" style={[pal.text, s.pb5, s.pl5]}> - That contains the following: + <Trans>That contains the following:</Trans> </Text> <View style={[styles.valueContainer, pal.btn]}> <View style={[styles.dnsValue]}> @@ -478,7 +478,9 @@ function CustomHandleForm({ <View style={styles.spacer} /> <Button type="default" style={[s.p20, s.mb10]} onPress={onPressCopy}> <Text type="xl" style={[pal.link, s.textCenter]}> - Copy {isDNSForm ? 'Domain Value' : 'File Contents'} + <Trans> + Copy {isDNSForm ? _(msg`Domain Value`) : _(msg`File Contents`)} + </Trans> </Text> </Button> {canSave === true && ( @@ -504,8 +506,8 @@ function CustomHandleForm({ ) : ( <Text type="xl-medium" style={[s.white, s.textCenter]}> {canSave - ? `Update to ${handle}` - : `Verify ${isDNSForm ? 'DNS Record' : 'Text File'}`} + ? _(msg`Update to ${handle}`) + : _(msg`Verify ${isDNSForm ? 'DNS Record' : 'Text File'}`)} </Text> )} </Button> @@ -513,9 +515,9 @@ function CustomHandleForm({ <TouchableOpacity onPress={onToggleCustom} accessibilityLabel={_(msg`Use default provider`)} - accessibilityHint="Use bsky.social as hosting provider"> + accessibilityHint={_(msg`Use bsky.social as hosting provider`)}> <Text type="md-medium" style={[pal.link, s.pl10, s.pt5]}> - Nevermind, create a handle for me + <Trans>Nevermind, create a handle for me</Trans> </Text> </TouchableOpacity> </> diff --git a/src/view/com/modals/ChangePassword.tsx b/src/view/com/modals/ChangePassword.tsx index d8add9794..4badc88aa 100644 --- a/src/view/com/modals/ChangePassword.tsx +++ b/src/view/com/modals/ChangePassword.tsx @@ -137,7 +137,9 @@ export function Component() { <View> <View style={styles.titleSection}> <Text type="title-lg" style={[pal.text, styles.title]}> - {stage !== Stages.Done ? 'Change Password' : 'Password Changed'} + {stage !== Stages.Done + ? _(msg`Change Password`) + : _(msg`Password Changed`)} </Text> </View> @@ -180,7 +182,7 @@ export function Component() { <TextInput testID="codeInput" style={[pal.text, styles.textInput]} - placeholder="Reset code" + placeholder={_(msg`Reset code`)} placeholderTextColor={pal.colors.textLight} value={resetCode} onChangeText={setResetCode} @@ -207,7 +209,7 @@ export function Component() { <TextInput testID="codeInput" style={[pal.text, styles.textInput]} - placeholder="New password" + placeholder={_(msg`New password`)} placeholderTextColor={pal.colors.textLight} onChangeText={setNewPassword} secureTextEntry diff --git a/src/view/com/modals/Confirm.tsx b/src/view/com/modals/Confirm.tsx deleted file mode 100644 index 307897fb8..000000000 --- a/src/view/com/modals/Confirm.tsx +++ /dev/null @@ -1,132 +0,0 @@ -import React, {useState} from 'react' -import { - ActivityIndicator, - StyleSheet, - TouchableOpacity, - View, -} from 'react-native' -import {Text} from '../util/text/Text' -import {s, colors} from 'lib/styles' -import {ErrorMessage} from '../util/error/ErrorMessage' -import {cleanError} from 'lib/strings/errors' -import {usePalette} from 'lib/hooks/usePalette' -import {isWeb} from 'platform/detection' -import {useLingui} from '@lingui/react' -import {Trans, msg} from '@lingui/macro' -import type {ConfirmModal} from '#/state/modals' -import {useModalControls} from '#/state/modals' - -export const snapPoints = ['50%'] - -export function Component({ - title, - message, - onPressConfirm, - onPressCancel, - confirmBtnText, - confirmBtnStyle, - cancelBtnText, -}: ConfirmModal) { - const pal = usePalette('default') - const {_} = useLingui() - const {closeModal} = useModalControls() - const [isProcessing, setIsProcessing] = useState<boolean>(false) - const [error, setError] = useState<string>('') - const onPress = async () => { - setError('') - setIsProcessing(true) - try { - await onPressConfirm() - closeModal() - return - } catch (e: any) { - setError(cleanError(e)) - setIsProcessing(false) - } - } - return ( - <View testID="confirmModal" style={[pal.view, styles.container]}> - <Text type="title-xl" style={[pal.text, styles.title]}> - {title} - </Text> - {typeof message === 'string' ? ( - <Text type="xl" style={[pal.textLight, styles.description]}> - {message} - </Text> - ) : ( - message() - )} - {error ? ( - <View style={s.mt10}> - <ErrorMessage message={error} /> - </View> - ) : undefined} - <View style={s.flex1} /> - {isProcessing ? ( - <View style={[styles.btn, s.mt10]}> - <ActivityIndicator /> - </View> - ) : ( - <TouchableOpacity - testID="confirmBtn" - onPress={onPress} - style={[styles.btn, confirmBtnStyle]} - accessibilityRole="button" - accessibilityLabel={_(msg({message: 'Confirm', context: 'action'}))} - accessibilityHint=""> - <Text style={[s.white, s.bold, s.f18]}> - {confirmBtnText ?? <Trans context="action">Confirm</Trans>} - </Text> - </TouchableOpacity> - )} - {onPressCancel === undefined ? null : ( - <TouchableOpacity - testID="cancelBtn" - onPress={onPressCancel} - style={[styles.btnCancel, s.mt10]} - accessibilityRole="button" - accessibilityLabel={_(msg({message: 'Cancel', context: 'action'}))} - accessibilityHint=""> - <Text type="button-lg" style={pal.textLight}> - {cancelBtnText ?? <Trans context="action">Cancel</Trans>} - </Text> - </TouchableOpacity> - )} - </View> - ) -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - padding: 10, - paddingBottom: isWeb ? 0 : 60, - }, - title: { - textAlign: 'center', - marginBottom: 12, - }, - description: { - textAlign: 'center', - paddingHorizontal: 22, - marginBottom: 10, - }, - btn: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'center', - borderRadius: 32, - padding: 14, - marginTop: 22, - marginHorizontal: 44, - backgroundColor: colors.blue3, - }, - btnCancel: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'center', - borderRadius: 32, - padding: 14, - marginHorizontal: 20, - }, -}) diff --git a/src/view/com/modals/ContentFilteringSettings.tsx b/src/view/com/modals/ContentFilteringSettings.tsx deleted file mode 100644 index 328d23dc2..000000000 --- a/src/view/com/modals/ContentFilteringSettings.tsx +++ /dev/null @@ -1,401 +0,0 @@ -import React from 'react' -import {LabelPreference} from '@atproto/api' -import {StyleSheet, Pressable, View, Linking} from 'react-native' -import LinearGradient from 'react-native-linear-gradient' -import {ScrollView} from './util' -import {s, colors, gradients} from 'lib/styles' -import {Text} from '../util/text/Text' -import {TextLink} from '../util/Link' -import {ToggleButton} from '../util/forms/ToggleButton' -import {Button} from '../util/forms/Button' -import {usePalette} from 'lib/hooks/usePalette' -import {isIOS} from 'platform/detection' -import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' -import * as Toast from '../util/Toast' -import {logger} from '#/logger' -import {Trans, msg} from '@lingui/macro' -import {useLingui} from '@lingui/react' -import {useModalControls} from '#/state/modals' -import { - usePreferencesQuery, - usePreferencesSetContentLabelMutation, - usePreferencesSetAdultContentMutation, - ConfigurableLabelGroup, - CONFIGURABLE_LABEL_GROUPS, - UsePreferencesQueryResponse, -} from '#/state/queries/preferences' - -export const snapPoints = ['90%'] - -export function Component({}: {}) { - const {isMobile} = useWebMediaQueries() - const pal = usePalette('default') - const {_} = useLingui() - const {closeModal} = useModalControls() - const {data: preferences} = usePreferencesQuery() - - const onPressDone = React.useCallback(() => { - closeModal() - }, [closeModal]) - - return ( - <View testID="contentFilteringModal" style={[pal.view, styles.container]}> - <Text style={[pal.text, styles.title]}> - <Trans>Content Filtering</Trans> - </Text> - - <ScrollView style={styles.scrollContainer}> - <AdultContentEnabledPref /> - <ContentLabelPref - preferences={preferences} - labelGroup="nsfw" - disabled={!preferences?.adultContentEnabled} - /> - <ContentLabelPref - preferences={preferences} - labelGroup="nudity" - disabled={!preferences?.adultContentEnabled} - /> - <ContentLabelPref - preferences={preferences} - labelGroup="suggestive" - disabled={!preferences?.adultContentEnabled} - /> - <ContentLabelPref - preferences={preferences} - labelGroup="gore" - disabled={!preferences?.adultContentEnabled} - /> - <ContentLabelPref preferences={preferences} labelGroup="hate" /> - <ContentLabelPref preferences={preferences} labelGroup="spam" /> - <ContentLabelPref - preferences={preferences} - labelGroup="impersonation" - /> - <View style={{height: isMobile ? 60 : 0}} /> - </ScrollView> - - <View - style={[ - styles.btnContainer, - isMobile && styles.btnContainerMobile, - pal.borderDark, - ]}> - <Pressable - testID="sendReportBtn" - onPress={onPressDone} - accessibilityRole="button" - accessibilityLabel={_(msg`Done`)} - accessibilityHint=""> - <LinearGradient - colors={[gradients.blueLight.start, gradients.blueLight.end]} - start={{x: 0, y: 0}} - end={{x: 1, y: 1}} - style={[styles.btn]}> - <Text style={[s.white, s.bold, s.f18]}> - <Trans>Done</Trans> - </Text> - </LinearGradient> - </Pressable> - </View> - </View> - ) -} - -function AdultContentEnabledPref() { - const pal = usePalette('default') - const {_} = useLingui() - const {data: preferences} = usePreferencesQuery() - const {mutate, variables} = usePreferencesSetAdultContentMutation() - const {openModal} = useModalControls() - - const onSetAge = React.useCallback( - () => openModal({name: 'birth-date-settings'}), - [openModal], - ) - - const onToggleAdultContent = React.useCallback(async () => { - if (isIOS) return - - try { - mutate({ - enabled: !(variables?.enabled ?? preferences?.adultContentEnabled), - }) - } catch (e) { - Toast.show( - _(msg`There was an issue syncing your preferences with the server`), - ) - logger.error('Failed to update preferences with server', {message: e}) - } - }, [variables, preferences, mutate, _]) - - const onAdultContentLinkPress = React.useCallback(() => { - Linking.openURL('https://bsky.app/') - }, []) - - return ( - <View style={s.mb10}> - {isIOS ? ( - preferences?.adultContentEnabled ? null : ( - <Text type="md" style={pal.textLight}> - <Trans> - Adult content can only be enabled via the Web at{' '} - <TextLink - style={pal.link} - href="" - text="bsky.app" - onPress={onAdultContentLinkPress} - /> - . - </Trans> - </Text> - ) - ) : typeof preferences?.birthDate === 'undefined' ? ( - <View style={[pal.viewLight, styles.agePrompt]}> - <Text type="md" style={[pal.text, {flex: 1}]}> - <Trans>Confirm your age to enable adult content.</Trans> - </Text> - <Button - type="primary" - label={_(msg({message: 'Set Age', context: 'action'}))} - onPress={onSetAge} - /> - </View> - ) : (preferences.userAge || 0) >= 18 ? ( - <ToggleButton - type="default-light" - label={_(msg`Enable Adult Content`)} - isSelected={variables?.enabled ?? preferences?.adultContentEnabled} - onPress={onToggleAdultContent} - style={styles.toggleBtn} - /> - ) : ( - <View style={[pal.viewLight, styles.agePrompt]}> - <Text type="md" style={[pal.text, {flex: 1}]}> - <Trans>You must be 18 or older to enable adult content.</Trans> - </Text> - <Button - type="primary" - label={_(msg({message: 'Set Age', context: 'action'}))} - onPress={onSetAge} - /> - </View> - )} - </View> - ) -} - -// TODO: Refactor this component to pass labels down to each tab -function ContentLabelPref({ - preferences, - labelGroup, - disabled, -}: { - preferences?: UsePreferencesQueryResponse - labelGroup: ConfigurableLabelGroup - disabled?: boolean -}) { - const pal = usePalette('default') - const visibility = preferences?.contentLabels?.[labelGroup] - const {mutate, variables} = usePreferencesSetContentLabelMutation() - - const onChange = React.useCallback( - (vis: LabelPreference) => { - mutate({labelGroup, visibility: vis}) - }, - [mutate, labelGroup], - ) - - return ( - <View style={[styles.contentLabelPref, pal.border]}> - <View style={s.flex1}> - <Text type="md-medium" style={[pal.text]}> - {CONFIGURABLE_LABEL_GROUPS[labelGroup].title} - </Text> - {typeof CONFIGURABLE_LABEL_GROUPS[labelGroup].subtitle === 'string' && ( - <Text type="sm" style={[pal.textLight]}> - {CONFIGURABLE_LABEL_GROUPS[labelGroup].subtitle} - </Text> - )} - </View> - - {disabled || !visibility ? ( - <Text type="sm-bold" style={pal.textLight}> - <Trans context="action">Hide</Trans> - </Text> - ) : ( - <SelectGroup - current={variables?.visibility || visibility} - onChange={onChange} - labelGroup={labelGroup} - /> - )} - </View> - ) -} - -interface SelectGroupProps { - current: LabelPreference - onChange: (v: LabelPreference) => void - labelGroup: ConfigurableLabelGroup -} - -function SelectGroup({current, onChange, labelGroup}: SelectGroupProps) { - const {_} = useLingui() - - return ( - <View style={styles.selectableBtns}> - <SelectableBtn - current={current} - value="hide" - label={_(msg`Hide`)} - left - onChange={onChange} - labelGroup={labelGroup} - /> - <SelectableBtn - current={current} - value="warn" - label={_(msg`Warn`)} - onChange={onChange} - labelGroup={labelGroup} - /> - <SelectableBtn - current={current} - value="ignore" - label={_(msg`Show`)} - right - onChange={onChange} - labelGroup={labelGroup} - /> - </View> - ) -} - -interface SelectableBtnProps { - current: string - value: LabelPreference - label: string - left?: boolean - right?: boolean - onChange: (v: LabelPreference) => void - labelGroup: ConfigurableLabelGroup -} - -function SelectableBtn({ - current, - value, - label, - left, - right, - onChange, - labelGroup, -}: SelectableBtnProps) { - const pal = usePalette('default') - const palPrimary = usePalette('inverted') - const {_} = useLingui() - - return ( - <Pressable - style={[ - styles.selectableBtn, - left && styles.selectableBtnLeft, - right && styles.selectableBtnRight, - pal.border, - current === value ? palPrimary.view : pal.view, - ]} - onPress={() => onChange(value)} - accessibilityRole="button" - accessibilityLabel={value} - accessibilityHint={_( - msg`Set ${value} for ${labelGroup} content moderation policy`, - )}> - <Text style={current === value ? palPrimary.text : pal.text}> - {label} - </Text> - </Pressable> - ) -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - }, - title: { - textAlign: 'center', - fontWeight: 'bold', - fontSize: 24, - marginBottom: 12, - }, - description: { - paddingHorizontal: 2, - marginBottom: 10, - }, - scrollContainer: { - flex: 1, - paddingHorizontal: 10, - }, - btnContainer: { - paddingTop: 10, - paddingHorizontal: 10, - }, - btnContainerMobile: { - paddingBottom: 40, - borderTopWidth: 1, - }, - - agePrompt: { - flexDirection: 'row', - justifyContent: 'space-between', - alignItems: 'center', - paddingLeft: 14, - paddingRight: 10, - paddingVertical: 8, - borderRadius: 8, - }, - - contentLabelPref: { - flexDirection: 'row', - justifyContent: 'space-between', - alignItems: 'center', - paddingTop: 14, - paddingLeft: 4, - marginBottom: 14, - borderTopWidth: 1, - }, - - selectableBtns: { - flexDirection: 'row', - marginLeft: 10, - }, - selectableBtn: { - flexDirection: 'row', - justifyContent: 'center', - borderWidth: 1, - borderLeftWidth: 0, - paddingHorizontal: 10, - paddingVertical: 10, - }, - selectableBtnLeft: { - borderTopLeftRadius: 8, - borderBottomLeftRadius: 8, - borderLeftWidth: 1, - }, - selectableBtnRight: { - borderTopRightRadius: 8, - borderBottomRightRadius: 8, - }, - - btn: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'center', - width: '100%', - borderRadius: 32, - padding: 14, - backgroundColor: colors.gray1, - }, - toggleBtn: { - paddingHorizontal: 0, - }, -}) diff --git a/src/view/com/modals/DeleteAccount.tsx b/src/view/com/modals/DeleteAccount.tsx index 40d78cfe0..2301e7a66 100644 --- a/src/view/com/modals/DeleteAccount.tsx +++ b/src/view/com/modals/DeleteAccount.tsx @@ -173,7 +173,7 @@ export function Component({}: {}) { </Text> <TextInput style={[styles.textInput, pal.borderDark, pal.text, styles.mb20]} - placeholder="Confirmation code" + placeholder={_(msg`Confirmation code`)} placeholderTextColor={pal.textLight.color} keyboardAppearance={theme.colorScheme} value={confirmCode} @@ -192,7 +192,7 @@ export function Component({}: {}) { </Text> <TextInput style={[styles.textInput, pal.borderDark, pal.text]} - placeholder="Password" + placeholder={_(msg`Password`)} placeholderTextColor={pal.textLight.color} keyboardAppearance={theme.colorScheme} secureTextEntry @@ -228,7 +228,7 @@ export function Component({}: {}) { onPress={onCancel} accessibilityRole="button" accessibilityLabel={_(msg`Cancel account deletion`)} - accessibilityHint="Exits account deletion process" + accessibilityHint={_(msg`Exits account deletion process`)} onAccessibilityEscape={onCancel}> <Text type="button-lg" style={pal.textLight}> <Trans context="action">Cancel</Trans> diff --git a/src/view/com/modals/InAppBrowserConsent.tsx b/src/view/com/modals/InAppBrowserConsent.tsx index 86bb46ca8..3fa515934 100644 --- a/src/view/com/modals/InAppBrowserConsent.tsx +++ b/src/view/com/modals/InAppBrowserConsent.tsx @@ -77,7 +77,7 @@ export function Component({href}: {href: string}) { }} accessibilityLabel={_(msg`Cancel`)} accessibilityHint="" - label="Cancel" + label={_(msg`Cancel`)} labelContainerStyle={{justifyContent: 'center', padding: 8}} labelStyle={[s.f18]} /> diff --git a/src/view/com/modals/LinkWarning.tsx b/src/view/com/modals/LinkWarning.tsx index 81fdc7285..b5ff6700d 100644 --- a/src/view/com/modals/LinkWarning.tsx +++ b/src/view/com/modals/LinkWarning.tsx @@ -73,8 +73,8 @@ export function Component({text, href}: {text: string; href: string}) { type="primary" onPress={onPressVisit} accessibilityLabel={_(msg`Visit Site`)} - accessibilityHint="" - label="Visit Site" + accessibilityHint={_(msg`Opens the linked website`)} + label={_(msg`Visit Site`)} labelContainerStyle={{justifyContent: 'center', padding: 4}} labelStyle={[s.f18]} /> @@ -85,8 +85,8 @@ export function Component({text, href}: {text: string; href: string}) { closeModal() }} accessibilityLabel={_(msg`Cancel`)} - accessibilityHint="" - label="Cancel" + accessibilityHint={_(msg`Cancels opening the linked website`)} + label={_(msg`Cancel`)} labelContainerStyle={{justifyContent: 'center', padding: 4}} labelStyle={[s.f18]} /> diff --git a/src/view/com/modals/ListAddRemoveUsers.tsx b/src/view/com/modals/ListAddRemoveUsers.tsx index 27c33f806..4715348dd 100644 --- a/src/view/com/modals/ListAddRemoveUsers.tsx +++ b/src/view/com/modals/ListAddRemoveUsers.tsx @@ -231,7 +231,11 @@ function UserResult({ width: 54, paddingLeft: 4, }}> - <UserAvatar size={40} avatar={profile.avatar} /> + <UserAvatar + size={40} + avatar={profile.avatar} + type={profile.associated?.labeler ? 'labeler' : 'user'} + /> </View> <View style={{ diff --git a/src/view/com/modals/Modal.tsx b/src/view/com/modals/Modal.tsx index 100444ff5..238cfc502 100644 --- a/src/view/com/modals/Modal.tsx +++ b/src/view/com/modals/Modal.tsx @@ -6,7 +6,6 @@ import {createCustomBackdrop} from '../util/BottomSheetCustomBackdrop' import {usePalette} from 'lib/hooks/usePalette' import {useModals, useModalControls} from '#/state/modals' -import * as ConfirmModal from './Confirm' import * as EditProfileModal from './EditProfile' import * as RepostModal from './Repost' import * as SelfLabelModal from './SelfLabel' @@ -16,17 +15,12 @@ import * as UserAddRemoveListsModal from './UserAddRemoveLists' import * as ListAddUserModal from './ListAddRemoveUsers' import * as AltImageModal from './AltImage' import * as EditImageModal from './AltImage' -import * as ReportModal from './report/Modal' -import * as AppealLabelModal from './AppealLabel' import * as DeleteAccountModal from './DeleteAccount' import * as ChangeHandleModal from './ChangeHandle' import * as InviteCodesModal from './InviteCodes' import * as AddAppPassword from './AddAppPasswords' -import * as ContentFilteringSettingsModal from './ContentFilteringSettings' import * as ContentLanguagesSettingsModal from './lang-settings/ContentLanguagesSettings' import * as PostLanguagesSettingsModal from './lang-settings/PostLanguagesSettings' -import * as ModerationDetailsModal from './ModerationDetails' -import * as BirthDateSettingsModal from './BirthDateSettings' import * as VerifyEmailModal from './VerifyEmail' import * as ChangeEmailModal from './ChangeEmail' import * as ChangePasswordModal from './ChangePassword' @@ -66,18 +60,9 @@ export function ModalsContainer() { let snapPoints: (string | number)[] = DEFAULT_SNAPPOINTS let element - if (activeModal?.name === 'confirm') { - snapPoints = ConfirmModal.snapPoints - element = <ConfirmModal.Component {...activeModal} /> - } else if (activeModal?.name === 'edit-profile') { + if (activeModal?.name === 'edit-profile') { snapPoints = EditProfileModal.snapPoints element = <EditProfileModal.Component {...activeModal} /> - } else if (activeModal?.name === 'report') { - snapPoints = ReportModal.snapPoints - element = <ReportModal.Component {...activeModal} /> - } else if (activeModal?.name === 'appeal-label') { - snapPoints = AppealLabelModal.snapPoints - element = <AppealLabelModal.Component {...activeModal} /> } else if (activeModal?.name === 'create-or-edit-list') { snapPoints = CreateOrEditListModal.snapPoints element = <CreateOrEditListModal.Component {...activeModal} /> @@ -114,21 +99,12 @@ export function ModalsContainer() { } else if (activeModal?.name === 'add-app-password') { snapPoints = AddAppPassword.snapPoints element = <AddAppPassword.Component /> - } else if (activeModal?.name === 'content-filtering-settings') { - snapPoints = ContentFilteringSettingsModal.snapPoints - element = <ContentFilteringSettingsModal.Component /> } else if (activeModal?.name === 'content-languages-settings') { snapPoints = ContentLanguagesSettingsModal.snapPoints element = <ContentLanguagesSettingsModal.Component /> } else if (activeModal?.name === 'post-languages-settings') { snapPoints = PostLanguagesSettingsModal.snapPoints element = <PostLanguagesSettingsModal.Component /> - } else if (activeModal?.name === 'moderation-details') { - snapPoints = ModerationDetailsModal.snapPoints - element = <ModerationDetailsModal.Component {...activeModal} /> - } else if (activeModal?.name === 'birth-date-settings') { - snapPoints = BirthDateSettingsModal.snapPoints - element = <BirthDateSettingsModal.Component /> } else if (activeModal?.name === 'verify-email') { snapPoints = VerifyEmailModal.snapPoints element = <VerifyEmailModal.Component {...activeModal} /> diff --git a/src/view/com/modals/Modal.web.tsx b/src/view/com/modals/Modal.web.tsx index 0ced894a1..7e5d548ac 100644 --- a/src/view/com/modals/Modal.web.tsx +++ b/src/view/com/modals/Modal.web.tsx @@ -7,10 +7,7 @@ import {useWebBodyScrollLock} from '#/lib/hooks/useWebBodyScrollLock' import {useModals, useModalControls} from '#/state/modals' import type {Modal as ModalIface} from '#/state/modals' -import * as ConfirmModal from './Confirm' import * as EditProfileModal from './EditProfile' -import * as ReportModal from './report/Modal' -import * as AppealLabelModal from './AppealLabel' import * as CreateOrEditListModal from './CreateOrEditList' import * as UserAddRemoveLists from './UserAddRemoveLists' import * as ListAddUserModal from './ListAddRemoveUsers' @@ -24,11 +21,8 @@ import * as EditImageModal from './EditImage' import * as ChangeHandleModal from './ChangeHandle' import * as InviteCodesModal from './InviteCodes' import * as AddAppPassword from './AddAppPasswords' -import * as ContentFilteringSettingsModal from './ContentFilteringSettings' import * as ContentLanguagesSettingsModal from './lang-settings/ContentLanguagesSettings' import * as PostLanguagesSettingsModal from './lang-settings/PostLanguagesSettings' -import * as ModerationDetailsModal from './ModerationDetails' -import * as BirthDateSettingsModal from './BirthDateSettings' import * as VerifyEmailModal from './VerifyEmail' import * as ChangeEmailModal from './ChangeEmail' import * as ChangePasswordModal from './ChangePassword' @@ -78,14 +72,8 @@ function Modal({modal}: {modal: ModalIface}) { } let element - if (modal.name === 'confirm') { - element = <ConfirmModal.Component {...modal} /> - } else if (modal.name === 'edit-profile') { + if (modal.name === 'edit-profile') { element = <EditProfileModal.Component {...modal} /> - } else if (modal.name === 'report') { - element = <ReportModal.Component {...modal} /> - } else if (modal.name === 'appeal-label') { - element = <AppealLabelModal.Component {...modal} /> } else if (modal.name === 'create-or-edit-list') { element = <CreateOrEditListModal.Component {...modal} /> } else if (modal.name === 'user-add-remove-lists') { @@ -108,8 +96,6 @@ function Modal({modal}: {modal: ModalIface}) { element = <InviteCodesModal.Component /> } else if (modal.name === 'add-app-password') { element = <AddAppPassword.Component /> - } else if (modal.name === 'content-filtering-settings') { - element = <ContentFilteringSettingsModal.Component /> } else if (modal.name === 'content-languages-settings') { element = <ContentLanguagesSettingsModal.Component /> } else if (modal.name === 'post-languages-settings') { @@ -118,10 +104,6 @@ function Modal({modal}: {modal: ModalIface}) { element = <AltTextImageModal.Component {...modal} /> } else if (modal.name === 'edit-image') { element = <EditImageModal.Component {...modal} /> - } else if (modal.name === 'moderation-details') { - element = <ModerationDetailsModal.Component {...modal} /> - } else if (modal.name === 'birth-date-settings') { - element = <BirthDateSettingsModal.Component /> } else if (modal.name === 'verify-email') { element = <VerifyEmailModal.Component {...modal} /> } else if (modal.name === 'change-email') { diff --git a/src/view/com/modals/ModerationDetails.tsx b/src/view/com/modals/ModerationDetails.tsx deleted file mode 100644 index f890d50dc..000000000 --- a/src/view/com/modals/ModerationDetails.tsx +++ /dev/null @@ -1,142 +0,0 @@ -import React from 'react' -import {StyleSheet, View} from 'react-native' -import {ModerationUI} from '@atproto/api' -import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' -import {s} from 'lib/styles' -import {Text} from '../util/text/Text' -import {TextLink} from '../util/Link' -import {usePalette} from 'lib/hooks/usePalette' -import {isWeb} from 'platform/detection' -import {listUriToHref} from 'lib/strings/url-helpers' -import {Button} from '../util/forms/Button' -import {useModalControls} from '#/state/modals' -import {useLingui} from '@lingui/react' -import {Trans, msg} from '@lingui/macro' - -export const snapPoints = [300] - -export function Component({ - context, - moderation, -}: { - context: 'account' | 'content' - moderation: ModerationUI -}) { - const {closeModal} = useModalControls() - const {isMobile} = useWebMediaQueries() - const pal = usePalette('default') - const {_} = useLingui() - - let name - let description - if (!moderation.cause) { - name = _(msg`Content Warning`) - description = _( - msg`Moderator has chosen to set a general warning on the content.`, - ) - } else if (moderation.cause.type === 'blocking') { - if (moderation.cause.source.type === 'list') { - const list = moderation.cause.source.list - name = _(msg`User Blocked by List`) - description = ( - <Trans> - This user is included in the{' '} - <TextLink - type="2xl" - href={listUriToHref(list.uri)} - text={list.name} - style={pal.link} - />{' '} - list which you have blocked. - </Trans> - ) - } else { - name = _(msg`User Blocked`) - description = _( - msg`You have blocked this user. You cannot view their content.`, - ) - } - } else if (moderation.cause.type === 'blocked-by') { - name = _(msg`User Blocks You`) - description = _( - msg`This user has blocked you. You cannot view their content.`, - ) - } else if (moderation.cause.type === 'block-other') { - name = _(msg`Content Not Available`) - description = _( - msg`This content is not available because one of the users involved has blocked the other.`, - ) - } else if (moderation.cause.type === 'muted') { - if (moderation.cause.source.type === 'list') { - const list = moderation.cause.source.list - name = _(msg`Account Muted by List`) - description = ( - <Trans> - This user is included in the{' '} - <TextLink - type="2xl" - href={listUriToHref(list.uri)} - text={list.name} - style={pal.link} - />{' '} - list which you have muted. - </Trans> - ) - } else { - name = _(msg`Account Muted`) - description = _(msg`You have muted this user.`) - } - } else { - name = moderation.cause.labelDef.strings[context].en.name - description = moderation.cause.labelDef.strings[context].en.description - } - - return ( - <View - testID="moderationDetailsModal" - style={[ - styles.container, - { - paddingHorizontal: isMobile ? 14 : 0, - }, - pal.view, - ]}> - <Text type="title-xl" style={[pal.text, styles.title]}> - {name} - </Text> - <Text type="2xl" style={[pal.text, styles.description]}> - {description} - </Text> - <View style={s.flex1} /> - <Button - type="primary" - style={styles.btn} - onPress={() => { - closeModal() - }}> - <Text type="button-lg" style={[pal.textLight, s.textCenter, s.white]}> - Okay - </Text> - </Button> - </View> - ) -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - }, - title: { - textAlign: 'center', - fontWeight: 'bold', - marginBottom: 12, - }, - description: { - textAlign: 'center', - }, - btn: { - paddingVertical: 14, - marginTop: isWeb ? 40 : 0, - marginBottom: isWeb ? 0 : 40, - }, -}) diff --git a/src/view/com/modals/SwitchAccount.tsx b/src/view/com/modals/SwitchAccount.tsx index c034c4b52..0658805bd 100644 --- a/src/view/com/modals/SwitchAccount.tsx +++ b/src/view/com/modals/SwitchAccount.tsx @@ -45,7 +45,11 @@ function SwitchAccountCard({account}: {account: SessionAccount}) { const contents = ( <View style={[pal.view, styles.linkCard]}> <View style={styles.avi}> - <UserAvatar size={40} avatar={profile?.avatar} /> + <UserAvatar + size={40} + avatar={profile?.avatar} + type={profile?.associated?.labeler ? 'labeler' : 'user'} + /> </View> <View style={[s.flex1]}> <Text type="md-bold" style={pal.text} numberOfLines={1}> diff --git a/src/view/com/modals/UserAddRemoveLists.tsx b/src/view/com/modals/UserAddRemoveLists.tsx index 8452f2513..8a61b1a70 100644 --- a/src/view/com/modals/UserAddRemoveLists.tsx +++ b/src/view/com/modals/UserAddRemoveLists.tsx @@ -180,7 +180,7 @@ function ListItem({ }, ]}> <View style={styles.listItemAvi}> - <UserAvatar size={40} avatar={list.avatar} /> + <UserAvatar size={40} avatar={list.avatar} type="list" /> </View> <View style={styles.listItemContent}> <Text diff --git a/src/view/com/modals/VerifyEmail.tsx b/src/view/com/modals/VerifyEmail.tsx index 30a57afc5..d3086d383 100644 --- a/src/view/com/modals/VerifyEmail.tsx +++ b/src/view/com/modals/VerifyEmail.tsx @@ -149,7 +149,7 @@ export function Component({showReminder}: {showReminder?: boolean}) { onPress={onEmailIncorrect} style={styles.changeEmailLink}> <Text type="lg" style={pal.link}> - Change + <Trans>Change</Trans> </Text> </Pressable> </> diff --git a/src/view/com/modals/crop-image/CropImage.web.tsx b/src/view/com/modals/crop-image/CropImage.web.tsx index 6f094a1fd..98a2494ed 100644 --- a/src/view/com/modals/crop-image/CropImage.web.tsx +++ b/src/view/com/modals/crop-image/CropImage.web.tsx @@ -100,7 +100,7 @@ export function Component({ onPress={doSetAs(AspectRatio.Wide)} accessibilityRole="button" accessibilityLabel={_(msg`Wide`)} - accessibilityHint="Sets image aspect ratio to wide"> + accessibilityHint={_(msg`Sets image aspect ratio to wide`)}> <RectWideIcon size={24} style={as === AspectRatio.Wide ? s.blue3 : pal.text} @@ -110,7 +110,7 @@ export function Component({ onPress={doSetAs(AspectRatio.Tall)} accessibilityRole="button" accessibilityLabel={_(msg`Tall`)} - accessibilityHint="Sets image aspect ratio to tall"> + accessibilityHint={_(msg`Sets image aspect ratio to tall`)}> <RectTallIcon size={24} style={as === AspectRatio.Tall ? s.blue3 : pal.text} @@ -120,7 +120,7 @@ export function Component({ onPress={doSetAs(AspectRatio.Square)} accessibilityRole="button" accessibilityLabel={_(msg`Square`)} - accessibilityHint="Sets image aspect ratio to square"> + accessibilityHint={_(msg`Sets image aspect ratio to square`)}> <SquareIcon size={24} style={as === AspectRatio.Square ? s.blue3 : pal.text} @@ -132,9 +132,9 @@ export function Component({ onPress={onPressCancel} accessibilityRole="button" accessibilityLabel={_(msg`Cancel image crop`)} - accessibilityHint="Exits image cropping process"> + accessibilityHint={_(msg`Exits image cropping process`)}> <Text type="xl" style={pal.link}> - Cancel + <Trans>Cancel</Trans> </Text> </TouchableOpacity> <View style={s.flex1} /> @@ -142,7 +142,7 @@ export function Component({ onPress={onPressDone} accessibilityRole="button" accessibilityLabel={_(msg`Save image crop`)} - accessibilityHint="Saves image crop settings"> + accessibilityHint={_(msg`Saves image crop settings`)}> <LinearGradient colors={[gradients.blueLight.start, gradients.blueLight.end]} start={{x: 0, y: 0}} diff --git a/src/view/com/modals/report/InputIssueDetails.tsx b/src/view/com/modals/report/InputIssueDetails.tsx deleted file mode 100644 index 2bc86f75e..000000000 --- a/src/view/com/modals/report/InputIssueDetails.tsx +++ /dev/null @@ -1,100 +0,0 @@ -import React from 'react' -import {View, TouchableOpacity, StyleSheet} from 'react-native' -import {TextInput} from '../util' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' -import {CharProgress} from '../../composer/char-progress/CharProgress' -import {Text} from '../../util/text/Text' -import {usePalette} from 'lib/hooks/usePalette' -import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' -import {s} from 'lib/styles' -import {SendReportButton} from './SendReportButton' -import {Trans, msg} from '@lingui/macro' -import {useLingui} from '@lingui/react' - -export function InputIssueDetails({ - details, - setDetails, - goBack, - submitReport, - isProcessing, -}: { - details: string | undefined - setDetails: (v: string) => void - goBack: () => void - submitReport: () => void - isProcessing: boolean -}) { - const pal = usePalette('default') - const {_} = useLingui() - const {isMobile} = useWebMediaQueries() - - return ( - <View - style={{ - marginTop: isMobile ? 12 : 0, - }}> - <TouchableOpacity - testID="addDetailsBtn" - style={[s.mb10, styles.backBtn]} - onPress={goBack} - accessibilityRole="button" - accessibilityLabel={_(msg`Add details`)} - accessibilityHint="Add more details to your report"> - <FontAwesomeIcon size={18} icon="angle-left" style={[pal.link]} /> - <Text style={[pal.text, s.f18, pal.link]}> - {' '} - <Trans>Back</Trans> - </Text> - </TouchableOpacity> - <View style={[pal.btn, styles.detailsInputContainer]}> - <TextInput - accessibilityLabel={_(msg`Text input field`)} - accessibilityHint="Enter a reason for reporting this post." - placeholder="Enter a reason or any other details here." - placeholderTextColor={pal.textLight.color} - value={details} - onChangeText={setDetails} - autoFocus={true} - numberOfLines={3} - multiline={true} - textAlignVertical="top" - maxLength={300} - style={[styles.detailsInput, pal.text]} - /> - <View style={styles.detailsInputBottomBar}> - <View style={styles.charCounter}> - <CharProgress count={details?.length || 0} /> - </View> - </View> - </View> - <SendReportButton onPress={submitReport} isProcessing={isProcessing} /> - </View> - ) -} - -const styles = StyleSheet.create({ - backBtn: { - flexDirection: 'row', - alignItems: 'center', - }, - detailsInputContainer: { - borderRadius: 8, - }, - detailsInput: { - paddingHorizontal: 12, - paddingTop: 12, - paddingBottom: 12, - borderRadius: 8, - minHeight: 100, - fontSize: 16, - }, - detailsInputBottomBar: { - alignSelf: 'flex-end', - }, - charCounter: { - flexDirection: 'row', - alignItems: 'center', - paddingRight: 10, - paddingBottom: 8, - }, -}) diff --git a/src/view/com/modals/report/Modal.tsx b/src/view/com/modals/report/Modal.tsx deleted file mode 100644 index abbad9b40..000000000 --- a/src/view/com/modals/report/Modal.tsx +++ /dev/null @@ -1,223 +0,0 @@ -import React, {useState, useMemo} from 'react' -import {Linking, StyleSheet, TouchableOpacity, View} from 'react-native' -import {ScrollView} from 'react-native-gesture-handler' -import {AtUri} from '@atproto/api' -import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' -import {s} from 'lib/styles' -import {Text} from '../../util/text/Text' -import * as Toast from '../../util/Toast' -import {ErrorMessage} from '../../util/error/ErrorMessage' -import {cleanError} from 'lib/strings/errors' -import {usePalette} from 'lib/hooks/usePalette' -import {SendReportButton} from './SendReportButton' -import {InputIssueDetails} from './InputIssueDetails' -import {ReportReasonOptions} from './ReasonOptions' -import {CollectionId} from './types' -import {Trans, msg} from '@lingui/macro' -import {useLingui} from '@lingui/react' -import {useModalControls} from '#/state/modals' -import {getAgent} from '#/state/session' - -const DMCA_LINK = 'https://bsky.social/about/support/copyright' - -export const snapPoints = [575] - -const CollectionNames = { - [CollectionId.FeedGenerator]: 'Feed', - [CollectionId.Profile]: 'Profile', - [CollectionId.List]: 'List', - [CollectionId.Post]: 'Post', -} - -type ReportComponentProps = - | { - uri: string - cid: string - } - | { - did: string - } - -export function Component(content: ReportComponentProps) { - const {closeModal} = useModalControls() - const pal = usePalette('default') - const {isMobile} = useWebMediaQueries() - const [isProcessing, setIsProcessing] = useState(false) - const [showDetailsInput, setShowDetailsInput] = useState(false) - const [error, setError] = useState<string>('') - const [issue, setIssue] = useState<string>('') - const [details, setDetails] = useState<string>('') - const isAccountReport = 'did' in content - const subjectKey = isAccountReport ? content.did : content.uri - const atUri = useMemo( - () => (!isAccountReport ? new AtUri(subjectKey) : null), - [isAccountReport, subjectKey], - ) - - const submitReport = async () => { - setError('') - if (!issue) { - return - } - setIsProcessing(true) - try { - if (issue === '__copyright__') { - Linking.openURL(DMCA_LINK) - closeModal() - return - } - const $type = !isAccountReport - ? 'com.atproto.repo.strongRef' - : 'com.atproto.admin.defs#repoRef' - await getAgent().createModerationReport({ - reasonType: issue, - subject: { - $type, - ...content, - }, - reason: details, - }) - Toast.show("Thank you for your report! We'll look into it promptly.") - - closeModal() - return - } catch (e: any) { - setError(cleanError(e)) - setIsProcessing(false) - } - } - - const goBack = () => { - setShowDetailsInput(false) - } - - return ( - <ScrollView testID="reportModal" style={[s.flex1, pal.view]}> - <View - style={[ - styles.container, - isMobile && { - paddingBottom: 40, - }, - ]}> - {showDetailsInput ? ( - <InputIssueDetails - details={details} - setDetails={setDetails} - goBack={goBack} - submitReport={submitReport} - isProcessing={isProcessing} - /> - ) : ( - <SelectIssue - setShowDetailsInput={setShowDetailsInput} - error={error} - issue={issue} - setIssue={setIssue} - submitReport={submitReport} - isProcessing={isProcessing} - atUri={atUri} - /> - )} - </View> - </ScrollView> - ) -} - -// If no atUri is passed, that means the reporting collection is account -const getCollectionNameForReport = (atUri: AtUri | null) => { - if (!atUri) return 'Account' - // Generic fallback for any collection being reported - return CollectionNames[atUri.collection as CollectionId] || 'Content' -} - -const SelectIssue = ({ - error, - setShowDetailsInput, - issue, - setIssue, - submitReport, - isProcessing, - atUri, -}: { - error: string | undefined - setShowDetailsInput: (v: boolean) => void - issue: string | undefined - setIssue: (v: string) => void - submitReport: () => void - isProcessing: boolean - atUri: AtUri | null -}) => { - const pal = usePalette('default') - const {_} = useLingui() - const collectionName = getCollectionNameForReport(atUri) - const onSelectIssue = (v: string) => setIssue(v) - const goToDetails = () => { - if (issue === '__copyright__') { - Linking.openURL(DMCA_LINK) - return - } - setShowDetailsInput(true) - } - - return ( - <> - <Text style={[pal.text, styles.title]}> - <Trans>Report {collectionName}</Trans> - </Text> - <Text style={[pal.textLight, styles.description]}> - <Trans>What is the issue with this {collectionName}?</Trans> - </Text> - <View style={{marginBottom: 10}}> - <ReportReasonOptions - atUri={atUri} - selectedIssue={issue} - onSelectIssue={onSelectIssue} - /> - </View> - {error ? <ErrorMessage message={error} /> : undefined} - {/* If no atUri is present, the report would be for account in which case, we allow sending without specifying a reason */} - {issue || !atUri ? ( - <> - <SendReportButton - onPress={submitReport} - isProcessing={isProcessing} - /> - <TouchableOpacity - testID="addDetailsBtn" - style={styles.addDetailsBtn} - onPress={goToDetails} - accessibilityRole="button" - accessibilityLabel={_(msg`Add details`)} - accessibilityHint="Add more details to your report"> - <Text style={[s.f18, pal.link]}> - <Trans>Add details to report</Trans> - </Text> - </TouchableOpacity> - </> - ) : undefined} - </> - ) -} - -const styles = StyleSheet.create({ - container: { - paddingHorizontal: 10, - }, - title: { - textAlign: 'center', - fontWeight: 'bold', - fontSize: 24, - marginBottom: 12, - }, - description: { - textAlign: 'center', - fontSize: 17, - paddingHorizontal: 22, - marginBottom: 10, - }, - addDetailsBtn: { - padding: 14, - alignSelf: 'center', - }, -}) diff --git a/src/view/com/modals/report/ReasonOptions.tsx b/src/view/com/modals/report/ReasonOptions.tsx deleted file mode 100644 index 23b49b664..000000000 --- a/src/view/com/modals/report/ReasonOptions.tsx +++ /dev/null @@ -1,123 +0,0 @@ -import {View} from 'react-native' -import React, {useMemo} from 'react' -import {AtUri, ComAtprotoModerationDefs} from '@atproto/api' - -import {Text} from '../../util/text/Text' -import {UsePaletteValue, usePalette} from 'lib/hooks/usePalette' -import {RadioGroup, RadioGroupItem} from 'view/com/util/forms/RadioGroup' -import {CollectionId} from './types' - -type ReasonMap = Record<string, {title: string; description: string}> -const CommonReasons = { - [ComAtprotoModerationDefs.REASONRUDE]: { - title: 'Anti-Social Behavior', - description: 'Harassment, trolling, or intolerance', - }, - [ComAtprotoModerationDefs.REASONVIOLATION]: { - title: 'Illegal and Urgent', - description: 'Glaring violations of law or terms of service', - }, - [ComAtprotoModerationDefs.REASONOTHER]: { - title: 'Other', - description: 'An issue not included in these options', - }, -} -const CollectionToReasonsMap: Record<string, ReasonMap> = { - [CollectionId.Post]: { - [ComAtprotoModerationDefs.REASONSPAM]: { - title: 'Spam', - description: 'Excessive mentions or replies', - }, - [ComAtprotoModerationDefs.REASONSEXUAL]: { - title: 'Unwanted Sexual Content', - description: 'Nudity or pornography not labeled as such', - }, - __copyright__: { - title: 'Copyright Violation', - description: 'Contains copyrighted material', - }, - ...CommonReasons, - }, - [CollectionId.List]: { - ...CommonReasons, - [ComAtprotoModerationDefs.REASONVIOLATION]: { - title: 'Name or Description Violates Community Standards', - description: 'Terms used violate community standards', - }, - }, -} -const AccountReportReasons = { - [ComAtprotoModerationDefs.REASONMISLEADING]: { - title: 'Misleading Account', - description: 'Impersonation or false claims about identity or affiliation', - }, - [ComAtprotoModerationDefs.REASONSPAM]: { - title: 'Frequently Posts Unwanted Content', - description: 'Spam; excessive mentions or replies', - }, - [ComAtprotoModerationDefs.REASONVIOLATION]: { - title: 'Name or Description Violates Community Standards', - description: 'Terms used violate community standards', - }, -} - -const Option = ({ - pal, - title, - description, -}: { - pal: UsePaletteValue - description: string - title: string -}) => { - return ( - <View> - <Text style={pal.text} type="md-bold"> - {title} - </Text> - <Text style={pal.textLight}>{description}</Text> - </View> - ) -} - -// This is mostly just content copy without almost any logic -// so this may grow over time and it makes sense to split it up into its own file -// to keep it separate from the actual reporting modal logic -const useReportRadioOptions = (pal: UsePaletteValue, atUri: AtUri | null) => - useMemo(() => { - let items: ReasonMap = {...CommonReasons} - // If no atUri is passed, that means the reporting collection is account - if (!atUri) { - items = {...AccountReportReasons} - } - - if (atUri?.collection && CollectionToReasonsMap[atUri.collection]) { - items = {...CollectionToReasonsMap[atUri.collection]} - } - - return Object.entries(items).map(([key, {title, description}]) => ({ - key, - label: <Option pal={pal} title={title} description={description} />, - })) - }, [pal, atUri]) - -export const ReportReasonOptions = ({ - atUri, - selectedIssue, - onSelectIssue, -}: { - atUri: AtUri | null - selectedIssue?: string - onSelectIssue: (key: string) => void -}) => { - const pal = usePalette('default') - const ITEMS: RadioGroupItem[] = useReportRadioOptions(pal, atUri) - return ( - <RadioGroup - items={ITEMS} - onSelect={onSelectIssue} - testID="reportReasonRadios" - initialSelection={selectedIssue} - /> - ) -} diff --git a/src/view/com/modals/report/SendReportButton.tsx b/src/view/com/modals/report/SendReportButton.tsx deleted file mode 100644 index 40c239bff..000000000 --- a/src/view/com/modals/report/SendReportButton.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import React from 'react' -import LinearGradient from 'react-native-linear-gradient' -import { - ActivityIndicator, - StyleSheet, - TouchableOpacity, - View, -} from 'react-native' -import {Text} from '../../util/text/Text' -import {s, gradients, colors} from 'lib/styles' -import {Trans, msg} from '@lingui/macro' -import {useLingui} from '@lingui/react' - -export function SendReportButton({ - onPress, - isProcessing, -}: { - onPress: () => void - isProcessing: boolean -}) { - const {_} = useLingui() - // loading state - // = - if (isProcessing) { - return ( - <View style={[styles.btn, s.mt10]}> - <ActivityIndicator /> - </View> - ) - } - return ( - <TouchableOpacity - testID="sendReportBtn" - style={s.mt10} - onPress={onPress} - accessibilityRole="button" - accessibilityLabel={_(msg`Report post`)} - accessibilityHint={`Reports post with reason and details`}> - <LinearGradient - colors={[gradients.blueLight.start, gradients.blueLight.end]} - start={{x: 0, y: 0}} - end={{x: 1, y: 1}} - style={[styles.btn]}> - <Text style={[s.white, s.bold, s.f18]}> - <Trans>Send Report</Trans> - </Text> - </LinearGradient> - </TouchableOpacity> - ) -} - -const styles = StyleSheet.create({ - btn: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'center', - width: '100%', - borderRadius: 32, - padding: 14, - backgroundColor: colors.gray1, - }, -}) diff --git a/src/view/com/modals/report/types.ts b/src/view/com/modals/report/types.ts deleted file mode 100644 index ca947ecbd..000000000 --- a/src/view/com/modals/report/types.ts +++ /dev/null @@ -1,8 +0,0 @@ -// TODO: ATM, @atproto/api does not export ids but it does have these listed at @atproto/api/client/lexicons -// once we start exporting the ids from the @atproto/ap package, replace these hardcoded ones -export enum CollectionId { - FeedGenerator = 'app.bsky.feed.generator', - Profile = 'app.bsky.actor.profile', - List = 'app.bsky.graph.list', - Post = 'app.bsky.feed.post', -} diff --git a/src/view/com/notifications/FeedItem.tsx b/src/view/com/notifications/FeedItem.tsx index 45166fe3c..78b1677c3 100644 --- a/src/view/com/notifications/FeedItem.tsx +++ b/src/view/com/notifications/FeedItem.tsx @@ -11,9 +11,10 @@ import { AppBskyFeedDefs, AppBskyFeedPost, ModerationOpts, - ProfileModeration, + ModerationDecision, moderateProfile, AppBskyEmbedRecordWithMedia, + AppBskyActorDefs, } from '@atproto/api' import {AtUri} from '@atproto/api' import { @@ -54,7 +55,8 @@ interface Author { handle: string displayName?: string avatar?: string - moderation: ProfileModeration + moderation: ModerationDecision + associated?: AppBskyActorDefs.ProfileAssociated } let FeedItem = ({ @@ -100,6 +102,7 @@ let FeedItem = ({ displayName: item.notification.author.displayName, avatar: item.notification.author.avatar, moderation: moderateProfile(item.notification.author, moderationOpts), + associated: item.notification.author.associated, }, ...(item.additional?.map(({author}) => { return { @@ -109,6 +112,7 @@ let FeedItem = ({ displayName: author.displayName, avatar: author.avatar, moderation: moderateProfile(author, moderationOpts), + associated: author.associated, } }) || []), ] @@ -182,7 +186,6 @@ let FeedItem = ({ testID={`feedItem-by-${item.notification.author.handle}`} style={[ styles.outer, - pal.view, pal.border, item.notification.isRead ? undefined @@ -337,7 +340,8 @@ function CondensedAuthorsList({ did={authors[0].did} handle={authors[0].handle} avatar={authors[0].avatar} - moderation={authors[0].moderation.avatar} + moderation={authors[0].moderation.ui('avatar')} + type={authors[0].associated?.labeler ? 'labeler' : 'user'} /> </View> ) @@ -355,7 +359,8 @@ function CondensedAuthorsList({ <UserAvatar size={35} avatar={author.avatar} - moderation={author.moderation.avatar} + moderation={author.moderation.ui('avatar')} + type={author.associated?.labeler ? 'labeler' : 'user'} /> </View> ))} @@ -413,7 +418,8 @@ function ExpandedAuthorsList({ <UserAvatar size={35} avatar={author.avatar} - moderation={author.moderation.avatar} + moderation={author.moderation.ui('avatar')} + type={author.associated?.labeler ? 'labeler' : 'user'} /> </View> <View style={s.flex1}> diff --git a/src/view/com/pager/FixedTouchableHighlight.tsx b/src/view/com/pager/FixedTouchableHighlight.tsx deleted file mode 100644 index d07196975..000000000 --- a/src/view/com/pager/FixedTouchableHighlight.tsx +++ /dev/null @@ -1,42 +0,0 @@ -// FixedTouchableHighlight.tsx -import React, {ComponentProps, useRef} from 'react' -import {GestureResponderEvent, TouchableHighlight} from 'react-native' - -type Position = {pageX: number; pageY: number} - -export default function FixedTouchableHighlight({ - onPress, - onPressIn, - ...props -}: ComponentProps<typeof TouchableHighlight>) { - const _touchActivatePositionRef = useRef<Position | null>(null) - - function _onPressIn(e: GestureResponderEvent) { - const {pageX, pageY} = e.nativeEvent - - _touchActivatePositionRef.current = { - pageX, - pageY, - } - - onPressIn?.(e) - } - - function _onPress(e: GestureResponderEvent) { - const {pageX, pageY} = e.nativeEvent - - const absX = Math.abs(_touchActivatePositionRef.current?.pageX! - pageX) - const absY = Math.abs(_touchActivatePositionRef.current?.pageY! - pageY) - - const dragged = absX > 2 || absY > 2 - if (!dragged) { - onPress?.(e) - } - } - - return ( - <TouchableHighlight onPressIn={_onPressIn} onPress={_onPress} {...props}> - {props.children} - </TouchableHighlight> - ) -} diff --git a/src/view/com/post-thread/PostLikedBy.tsx b/src/view/com/post-thread/PostLikedBy.tsx index 55463dc13..0760ed7ff 100644 --- a/src/view/com/post-thread/PostLikedBy.tsx +++ b/src/view/com/post-thread/PostLikedBy.tsx @@ -8,7 +8,7 @@ import {ProfileCardWithFollowBtn} from '../profile/ProfileCard' import {logger} from '#/logger' import {LoadingScreen} from '../util/LoadingScreen' import {useResolveUriQuery} from '#/state/queries/resolve-uri' -import {usePostLikedByQuery} from '#/state/queries/post-liked-by' +import {useLikedByQuery} from '#/state/queries/post-liked-by' import {cleanError} from '#/lib/strings/errors' export function PostLikedBy({uri}: {uri: string}) { @@ -28,7 +28,7 @@ export function PostLikedBy({uri}: {uri: string}) { isError, error, refetch, - } = usePostLikedByQuery(resolvedUri?.uri) + } = useLikedByQuery(resolvedUri?.uri) const likes = useMemo(() => { if (data?.pages) { return data.pages.flatMap(page => page.likes) diff --git a/src/view/com/post-thread/PostThread.tsx b/src/view/com/post-thread/PostThread.tsx index a7ee42a94..8042e7bd5 100644 --- a/src/view/com/post-thread/PostThread.tsx +++ b/src/view/com/post-thread/PostThread.tsx @@ -1,25 +1,14 @@ import React, {useEffect, useRef} from 'react' -import { - ActivityIndicator, - Pressable, - StyleSheet, - TouchableOpacity, - View, -} from 'react-native' +import {StyleSheet, useWindowDimensions, View} from 'react-native' import {AppBskyFeedDefs} from '@atproto/api' -import {CenteredView} from '../util/Views' -import {LoadingScreen} from '../util/LoadingScreen' +import {Trans, msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' + import {List, ListMethods} from '../util/List' -import { - FontAwesomeIcon, - FontAwesomeIconStyle, -} from '@fortawesome/react-native-fontawesome' import {PostThreadItem} from './PostThreadItem' import {ComposePrompt} from '../composer/Prompt' import {ViewHeader} from '../util/ViewHeader' -import {ErrorMessage} from '../util/error/ErrorMessage' import {Text} from '../util/text/Text' -import {s} from 'lib/styles' import {usePalette} from 'lib/hooks/usePalette' import {useSetTitle} from 'lib/hooks/useSetTitle' import { @@ -30,21 +19,18 @@ import { usePostThreadQuery, sortThread, } from '#/state/queries/post-thread' -import {useNavigation} from '@react-navigation/native' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' -import {NavigationProp} from 'lib/routes/types' import {sanitizeDisplayName} from 'lib/strings/display-names' -import {cleanError} from '#/lib/strings/errors' -import {Trans, msg} from '@lingui/macro' -import {useLingui} from '@lingui/react' import { - UsePreferencesQueryResponse, useModerationOpts, usePreferencesQuery, } from '#/state/queries/preferences' import {useSession} from '#/state/session' import {isAndroid, isNative, isWeb} from '#/platform/detection' import {moderatePost_wrapped as moderatePost} from '#/lib/moderatePost_wrapped' +import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender' +import {ListFooter, ListMaybePlaceholder} from '#/components/Lists' +import {cleanError} from 'lib/strings/errors' // FlatList maintainVisibleContentPosition breaks if too many items // are prepended. This seems to be an optimal number based on *shrug*. @@ -58,9 +44,7 @@ const MAINTAIN_VISIBLE_CONTENT_POSITION = { const TOP_COMPONENT = {_reactKey: '__top_component__'} const REPLY_PROMPT = {_reactKey: '__reply__'} -const CHILD_SPINNER = {_reactKey: '__child_spinner__'} const LOAD_MORE = {_reactKey: '__load_more__'} -const BOTTOM_COMPONENT = {_reactKey: '__bottom_component__'} type YieldedItem = ThreadPost | ThreadBlocked | ThreadNotFound type RowItem = @@ -68,9 +52,7 @@ type RowItem = // TODO: TS doesn't actually enforce it's one of these, it only enforces matching shape. | typeof TOP_COMPONENT | typeof REPLY_PROMPT - | typeof CHILD_SPINNER | typeof LOAD_MORE - | typeof BOTTOM_COMPONENT type ThreadSkeletonParts = { parents: YieldedItem[] @@ -78,6 +60,10 @@ type ThreadSkeletonParts = { replies: YieldedItem[] } +const keyExtractor = (item: RowItem) => { + return item._reactKey +} + export function PostThread({ uri, onCanReply, @@ -85,17 +71,30 @@ export function PostThread({ }: { uri: string | undefined onCanReply: (canReply: boolean) => void - onPressReply: () => void + onPressReply: () => unknown }) { + const {hasSession} = useSession() + const {_} = useLingui() + const pal = usePalette('default') + const {isMobile, isTabletOrMobile} = useWebMediaQueries() + const initialNumToRender = useInitialNumToRender() + const {height: windowHeight} = useWindowDimensions() + + const {data: preferences} = usePreferencesQuery() const { - isLoading, - isError, - error, + isFetching, + isError: isThreadError, + error: threadError, refetch, data: thread, } = usePostThreadQuery(uri) - const {data: preferences} = usePreferencesQuery() + const treeView = React.useMemo( + () => + !!preferences?.threadViewPrefs?.lab_treeViewEnabled && + hasBranchingReplies(thread), + [preferences?.threadViewPrefs, thread], + ) const rootPost = thread?.type === 'post' ? thread.post : undefined const rootPostRecord = thread?.type === 'post' ? thread.record : undefined @@ -105,14 +104,22 @@ export function PostThread({ rootPost && moderationOpts ? moderatePost(rootPost, moderationOpts) : undefined - - const cause = mod?.content.cause - - return cause - ? cause.type === 'label' && cause.labelDef.id === '!no-unauthenticated' - : false + return !!mod + ?.ui('contentList') + .blurs.find( + cause => + cause.type === 'label' && cause.labelDef.id === '!no-unauthenticated', + ) }, [rootPost, moderationOpts]) + // Values used for proper rendering of parents + const ref = useRef<ListMethods>(null) + const highlightedPostRef = useRef<View | null>(null) + const [maxParents, setMaxParents] = React.useState( + isWeb ? Infinity : PARENTS_CHUNK_SIZE, + ) + const [maxReplies, setMaxReplies] = React.useState(50) + useSetTitle( rootPost && !isNoPwi ? `${sanitizeDisplayName( @@ -120,62 +127,6 @@ export function PostThread({ )}: "${rootPostRecord!.text}"` : '', ) - useEffect(() => { - if (rootPost) { - onCanReply(!rootPost.viewer?.replyDisabled) - } - }, [rootPost, onCanReply]) - - if (isError || AppBskyFeedDefs.isNotFoundPost(thread)) { - return ( - <PostThreadError - error={error} - notFound={AppBskyFeedDefs.isNotFoundPost(thread)} - onRefresh={refetch} - /> - ) - } - if (AppBskyFeedDefs.isBlockedPost(thread)) { - return <PostThreadBlocked /> - } - if (!thread || isLoading || !preferences) { - return <LoadingScreen /> - } - return ( - <PostThreadLoaded - thread={thread} - threadViewPrefs={preferences.threadViewPrefs} - onRefresh={refetch} - onPressReply={onPressReply} - /> - ) -} - -function PostThreadLoaded({ - thread, - threadViewPrefs, - onRefresh, - onPressReply, -}: { - thread: ThreadNode - threadViewPrefs: UsePreferencesQueryResponse['threadViewPrefs'] - onRefresh: () => void - onPressReply: () => void -}) { - const {hasSession} = useSession() - const {_} = useLingui() - const pal = usePalette('default') - const {isMobile, isTabletOrMobile} = useWebMediaQueries() - const ref = useRef<ListMethods>(null) - const highlightedPostRef = useRef<View | null>(null) - const [maxParents, setMaxParents] = React.useState( - isWeb ? Infinity : PARENTS_CHUNK_SIZE, - ) - const [maxReplies, setMaxReplies] = React.useState(100) - const treeView = React.useMemo( - () => !!threadViewPrefs.lab_treeViewEnabled && hasBranchingReplies(thread), - [threadViewPrefs, thread], - ) // On native, this is going to start out `true`. We'll toggle it to `false` after the initial render if flushed. // This ensures that the first render contains no parents--even if they are already available in the cache. @@ -183,18 +134,56 @@ function PostThreadLoaded({ // On the web this is not necessary because we can synchronously adjust the scroll in onContentSizeChange instead. const [deferParents, setDeferParents] = React.useState(isNative) - const skeleton = React.useMemo( - () => - createThreadSkeleton( - sortThread(thread, threadViewPrefs), - hasSession, - treeView, - ), - [thread, threadViewPrefs, hasSession, treeView], - ) + const skeleton = React.useMemo(() => { + const threadViewPrefs = preferences?.threadViewPrefs + if (!threadViewPrefs || !thread) return null + + return createThreadSkeleton( + sortThread(thread, threadViewPrefs), + hasSession, + treeView, + ) + }, [thread, preferences?.threadViewPrefs, hasSession, treeView]) + + const error = React.useMemo(() => { + if (AppBskyFeedDefs.isNotFoundPost(thread)) { + return { + title: _(msg`Post not found`), + message: _(msg`The post may have been deleted.`), + } + } else if (skeleton?.highlightedPost.type === 'blocked') { + return { + title: _(msg`Post hidden`), + message: _( + msg`You have blocked the author or you have been blocked by the author.`, + ), + } + } else if (threadError?.message.startsWith('Post not found')) { + return { + title: _(msg`Post not found`), + message: _(msg`The post may have been deleted.`), + } + } else if (isThreadError) { + return { + message: threadError ? cleanError(threadError) : undefined, + } + } + + return null + }, [thread, skeleton?.highlightedPost, isThreadError, _, threadError]) + + useEffect(() => { + if (error) { + onCanReply(false) + } else if (rootPost) { + onCanReply(!rootPost.viewer?.replyDisabled) + } + }, [rootPost, onCanReply, error]) // construct content const posts = React.useMemo(() => { + if (!skeleton) return [] + const {parents, highlightedPost, replies} = skeleton let arr: RowItem[] = [] if (highlightedPost.type === 'post') { @@ -230,17 +219,11 @@ function PostThreadLoaded({ if (!highlightedPost.post.viewer?.replyDisabled) { arr.push(REPLY_PROMPT) } - if (highlightedPost.ctx.isChildLoading) { - arr.push(CHILD_SPINNER) - } else { - for (let i = 0; i < replies.length; i++) { - arr.push(replies[i]) - if (i === maxReplies) { - arr.push(LOAD_MORE) - break - } + for (let i = 0; i < replies.length; i++) { + arr.push(replies[i]) + if (i === maxReplies) { + break } - arr.push(BOTTOM_COMPONENT) } } return arr @@ -255,7 +238,7 @@ function PostThreadLoaded({ return } // wait for loading to finish - if (thread.type === 'post' && !!thread.parent) { + if (thread?.type === 'post' && !!thread.parent) { function onMeasure(pageY: number) { ref.current?.scrollToOffset({ animated: false, @@ -279,10 +262,10 @@ function PostThreadLoaded({ // To work around this, we prepend rows after scroll bumps against the top and rests. const needsBumpMaxParents = React.useRef(false) const onStartReached = React.useCallback(() => { - if (maxParents < skeleton.parents.length) { + if (skeleton?.parents && maxParents < skeleton.parents.length) { needsBumpMaxParents.current = true } - }, [maxParents, skeleton.parents.length]) + }, [maxParents, skeleton?.parents]) const bumpMaxParentsIfNeeded = React.useCallback(() => { if (!isNative) { return @@ -295,6 +278,11 @@ function PostThreadLoaded({ const onMomentumScrollEnd = bumpMaxParentsIfNeeded const onScrollToTop = bumpMaxParentsIfNeeded + const onEndReached = React.useCallback(() => { + if (isFetching || posts.length < maxReplies) return + setMaxReplies(prev => prev + 50) + }, [isFetching, maxReplies, posts.length]) + const renderItem = React.useCallback( ({item, index}: {item: RowItem; index: number}) => { if (item === TOP_COMPONENT) { @@ -325,46 +313,6 @@ function PostThreadLoaded({ </Text> </View> ) - } else if (item === LOAD_MORE) { - return ( - <Pressable - onPress={() => setMaxReplies(n => n + 50)} - style={[pal.border, pal.view, styles.itemContainer]} - accessibilityLabel={_(msg`Load more posts`)} - accessibilityHint=""> - <View - style={[ - pal.viewLight, - {paddingHorizontal: 18, paddingVertical: 14, borderRadius: 6}, - ]}> - <Text type="lg-medium" style={pal.text}> - <Trans>Load more posts</Trans> - </Text> - </View> - </Pressable> - ) - } else if (item === BOTTOM_COMPONENT) { - // HACK - // due to some complexities with how flatlist works, this is the easiest way - // I could find to get a border positioned directly under the last item - // -prf - return ( - <View - // @ts-ignore web-only - style={{ - // Leave enough space below that the scroll doesn't jump - height: isNative ? 600 : '100vh', - borderTopWidth: 1, - borderColor: pal.colors.border, - }} - /> - ) - } else if (item === CHILD_SPINNER) { - return ( - <View style={[pal.border, styles.childSpinner]}> - <ActivityIndicator /> - </View> - ) } else if (isThreadPost(item)) { const prev = isThreadPost(posts[index - 1]) ? (posts[index - 1] as ThreadPost) @@ -373,7 +321,9 @@ function PostThreadLoaded({ ? (posts[index - 1] as ThreadPost) : undefined const hasUnrevealedParents = - index === 0 && maxParents < skeleton.parents.length + index === 0 && + skeleton?.parents && + maxParents < skeleton.parents.length return ( <View ref={item.ctx.isHighlightedPost ? highlightedPostRef : undefined} @@ -390,9 +340,9 @@ function PostThreadLoaded({ showChildReplyLine={item.ctx.showChildReplyLine} showParentReplyLine={item.ctx.showParentReplyLine} hasPrecedingItem={ - !!prev?.ctx.showChildReplyLine || hasUnrevealedParents + !!prev?.ctx.showChildReplyLine || !!hasUnrevealedParents } - onPostReply={onRefresh} + onPostReply={refetch} /> </View> ) @@ -402,142 +352,62 @@ function PostThreadLoaded({ [ hasSession, isTabletOrMobile, + _, isMobile, onPressReply, pal.border, pal.viewLight, pal.textLight, - pal.view, - pal.text, - pal.colors.border, posts, - onRefresh, + skeleton?.parents, + maxParents, deferParents, treeView, - skeleton.parents.length, - maxParents, - _, + refetch, ], ) return ( - <List - ref={ref} - data={posts} - keyExtractor={item => item._reactKey} - renderItem={renderItem} - onContentSizeChange={isNative ? undefined : onContentSizeChangeWeb} - onStartReached={onStartReached} - onMomentumScrollEnd={onMomentumScrollEnd} - onScrollToTop={onScrollToTop} - maintainVisibleContentPosition={ - isNative ? MAINTAIN_VISIBLE_CONTENT_POSITION : undefined - } - style={s.hContentRegion} - // @ts-ignore our .web version only -prf - desktopFixedHeight - removeClippedSubviews={isAndroid ? false : undefined} - windowSize={11} - /> - ) -} - -function PostThreadBlocked() { - const {_} = useLingui() - const pal = usePalette('default') - const navigation = useNavigation<NavigationProp>() - - const onPressBack = React.useCallback(() => { - if (navigation.canGoBack()) { - navigation.goBack() - } else { - navigation.navigate('Home') - } - }, [navigation]) - - return ( - <CenteredView> - <View style={[pal.view, pal.border, styles.notFoundContainer]}> - <Text type="title-lg" style={[pal.text, s.mb5]}> - <Trans>Post hidden</Trans> - </Text> - <Text type="md" style={[pal.text, s.mb10]}> - <Trans> - You have blocked the author or you have been blocked by the author. - </Trans> - </Text> - <TouchableOpacity - onPress={onPressBack} - accessibilityRole="button" - accessibilityLabel={_(msg`Back`)} - accessibilityHint=""> - <Text type="2xl" style={pal.link}> - <FontAwesomeIcon - icon="angle-left" - style={[pal.link as FontAwesomeIconStyle, s.mr5]} - size={14} + <> + <ListMaybePlaceholder + isLoading={!preferences || !thread} + isError={!!error} + onRetry={refetch} + errorTitle={error?.title} + errorMessage={error?.message} + /> + {!error && thread && ( + <List + ref={ref} + data={posts} + renderItem={renderItem} + keyExtractor={keyExtractor} + onContentSizeChange={isNative ? undefined : onContentSizeChangeWeb} + onStartReached={onStartReached} + onEndReached={onEndReached} + onEndReachedThreshold={2} + onMomentumScrollEnd={onMomentumScrollEnd} + onScrollToTop={onScrollToTop} + maintainVisibleContentPosition={ + isNative ? MAINTAIN_VISIBLE_CONTENT_POSITION : undefined + } + // @ts-ignore our .web version only -prf + desktopFixedHeight + removeClippedSubviews={isAndroid ? false : undefined} + ListFooterComponent={ + <ListFooter + isFetching={isFetching} + onRetry={refetch} + // 300 is based on the minimum height of a post. This is enough extra height for the `maintainVisPos` to + // work without causing weird jumps on web or glitches on native + height={windowHeight - 200} /> - <Trans context="action">Back</Trans> - </Text> - </TouchableOpacity> - </View> - </CenteredView> - ) -} - -function PostThreadError({ - onRefresh, - notFound, - error, -}: { - onRefresh: () => void - notFound: boolean - error: Error | null -}) { - const {_} = useLingui() - const pal = usePalette('default') - const navigation = useNavigation<NavigationProp>() - - const onPressBack = React.useCallback(() => { - if (navigation.canGoBack()) { - navigation.goBack() - } else { - navigation.navigate('Home') - } - }, [navigation]) - - if (notFound) { - return ( - <CenteredView> - <View style={[pal.view, pal.border, styles.notFoundContainer]}> - <Text type="title-lg" style={[pal.text, s.mb5]}> - <Trans>Post not found</Trans> - </Text> - <Text type="md" style={[pal.text, s.mb10]}> - <Trans>The post may have been deleted.</Trans> - </Text> - <TouchableOpacity - onPress={onPressBack} - accessibilityRole="button" - accessibilityLabel={_(msg`Back`)} - accessibilityHint=""> - <Text type="2xl" style={pal.link}> - <FontAwesomeIcon - icon="angle-left" - style={[pal.link as FontAwesomeIconStyle, s.mr5]} - size={14} - /> - <Trans>Back</Trans> - </Text> - </TouchableOpacity> - </View> - </CenteredView> - ) - } - return ( - <CenteredView> - <ErrorMessage message={cleanError(error)} onPressTryAgain={onRefresh} /> - </CenteredView> + } + initialNumToRender={initialNumToRender} + windowSize={11} + /> + )} + </> ) } @@ -557,7 +427,9 @@ function createThreadSkeleton( node: ThreadNode, hasSession: boolean, treeView: boolean, -): ThreadSkeletonParts { +): ThreadSkeletonParts | null { + if (!node) return null + return { parents: Array.from(flattenThreadParents(node, hasSession)), highlightedPost: node, @@ -614,7 +486,10 @@ function hasPwiOptOut(node: ThreadPost) { return !!node.post.author.labels?.find(l => l.val === '!no-unauthenticated') } -function hasBranchingReplies(node: ThreadNode) { +function hasBranchingReplies(node?: ThreadNode) { + if (!node) { + return false + } if (node.type !== 'post') { return false } @@ -628,20 +503,9 @@ function hasBranchingReplies(node: ThreadNode) { } const styles = StyleSheet.create({ - notFoundContainer: { - margin: 10, - paddingHorizontal: 18, - paddingVertical: 14, - borderRadius: 6, - }, itemContainer: { borderTopWidth: 1, paddingHorizontal: 18, paddingVertical: 18, }, - childSpinner: { - borderTopWidth: 1, - paddingTop: 40, - paddingBottom: 200, - }, }) diff --git a/src/view/com/post-thread/PostThreadFollowBtn.tsx b/src/view/com/post-thread/PostThreadFollowBtn.tsx index e5b747cc9..45c3771f5 100644 --- a/src/view/com/post-thread/PostThreadFollowBtn.tsx +++ b/src/view/com/post-thread/PostThreadFollowBtn.tsx @@ -42,7 +42,10 @@ function PostThreadFollowBtnLoaded({ const {isTabletOrDesktop} = useWebMediaQueries() const profile: Shadow<AppBskyActorDefs.ProfileViewBasic> = useProfileShadow(profileUnshadowed) - const [queueFollow, queueUnfollow] = useProfileFollowMutationQueue(profile) + const [queueFollow, queueUnfollow] = useProfileFollowMutationQueue( + profile, + 'PostThreadItem', + ) const requireAuth = useRequireAuth() const isFollowing = !!profile.viewer?.following diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx index 9522ea6a0..6555bdf73 100644 --- a/src/view/com/post-thread/PostThreadItem.tsx +++ b/src/view/com/post-thread/PostThreadItem.tsx @@ -5,7 +5,7 @@ import { AppBskyFeedDefs, AppBskyFeedPost, RichText as RichTextAPI, - PostModeration, + ModerationDecision, } from '@atproto/api' import {moderatePost_wrapped as moderatePost} from '#/lib/moderatePost_wrapped' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' @@ -19,14 +19,14 @@ import {niceDate} from 'lib/strings/time' import {sanitizeDisplayName} from 'lib/strings/display-names' import {sanitizeHandle} from 'lib/strings/handles' import {countLines, pluralize} from 'lib/strings/helpers' -import {isEmbedByEmbedder} from 'lib/embeds' import {getTranslatorLink, isPostInLanguage} from '../../../locale/helpers' import {PostMeta} from '../util/PostMeta' import {PostEmbeds} from '../util/post-embeds' import {PostCtrls} from '../util/post-ctrls/PostCtrls' -import {PostHider} from '../util/moderation/PostHider' -import {ContentHider} from '../util/moderation/ContentHider' -import {PostAlerts} from '../util/moderation/PostAlerts' +import {PostHider} from '../../../components/moderation/PostHider' +import {ContentHider} from '../../../components/moderation/ContentHider' +import {PostAlerts} from '../../../components/moderation/PostAlerts' +import {LabelsOnMyPost} from '../../../components/moderation/LabelsOnMe' import {ErrorMessage} from '../util/error/ErrorMessage' import {usePalette} from 'lib/hooks/usePalette' import {formatCount} from '../util/numeric/format' @@ -147,7 +147,7 @@ let PostThreadItemLoaded = ({ post: Shadow<AppBskyFeedDefs.PostView> record: AppBskyFeedPost.Record richText: RichTextAPI - moderation: PostModeration + moderation: ModerationDecision treeView: boolean depth: number prevPost: ThreadPost | undefined @@ -175,7 +175,6 @@ let PostThreadItemLoaded = ({ const itemTitle = _(msg`Post by ${post.author.handle}`) const authorHref = makeProfileLink(post.author) const authorTitle = post.author.handle - const isAuthorMuted = post.author.viewer?.muted const likesHref = React.useMemo(() => { const urip = new AtUri(post.uri) return makeProfileLink(post.author, 'post', urip.rkey, 'liked-by') @@ -206,11 +205,7 @@ let PostThreadItemLoaded = ({ uri: post.uri, cid: post.cid, text: record.text, - author: { - handle: post.author.handle, - displayName: post.author.displayName, - avatar: post.author.avatar, - }, + author: post.author, embed: post.embed, moderation, }, @@ -256,7 +251,8 @@ let PostThreadItemLoaded = ({ did={post.author.did} handle={post.author.handle} avatar={post.author.avatar} - moderation={moderation.avatar} + moderation={moderation.ui('avatar')} + type={post.author.associated?.labeler ? 'labeler' : 'user'} /> </View> <View style={styles.layoutContent}> @@ -271,35 +267,12 @@ let PostThreadItemLoaded = ({ {sanitizeDisplayName( post.author.displayName || sanitizeHandle(post.author.handle), + moderation.ui('displayName'), )} </Text> </Link> </View> <View style={styles.meta}> - {isAuthorMuted && ( - <View - style={[ - pal.viewLight, - { - flexDirection: 'row', - alignItems: 'center', - gap: 4, - borderRadius: 6, - paddingHorizontal: 6, - paddingVertical: 2, - marginRight: 4, - }, - ]}> - <FontAwesomeIcon - icon={['far', 'eye-slash']} - size={12} - color={pal.colors.textLight} - /> - <Text type="sm-medium" style={pal.textLight}> - Muted - </Text> - </View> - )} <Link style={s.flex1} href={authorHref} title={authorTitle}> <Text type="md" style={[pal.textLight]} numberOfLines={1}> {sanitizeHandle(post.author.handle, '@')} @@ -312,15 +285,16 @@ let PostThreadItemLoaded = ({ )} </View> <View style={[s.pl10, s.pr10, s.pb10]}> + <LabelsOnMyPost post={post} /> <ContentHider - moderation={moderation.content} + modui={moderation.ui('contentView')} ignoreMute style={styles.contentHider} childContainerStyle={styles.contentHiderChild}> <PostAlerts - moderation={moderation.content} + modui={moderation.ui('contentView')} includeMute - style={styles.alert} + style={[a.pt_2xs, a.pb_sm]} /> {richText?.text ? ( <View @@ -338,18 +312,9 @@ let PostThreadItemLoaded = ({ </View> ) : undefined} {post.embed && ( - <ContentHider - moderation={moderation.embed} - moderationDecisions={moderation.decisions} - ignoreMute={isEmbedByEmbedder(post.embed, post.author.did)} - ignoreQuoteDecisions - style={s.mb10}> - <PostEmbeds - embed={post.embed} - moderation={moderation.embed} - moderationDecisions={moderation.decisions} - /> - </ContentHider> + <View style={[a.pb_sm]}> + <PostEmbeds embed={post.embed} moderation={moderation} /> + </View> )} </ContentHider> <ExpandedPostDetails @@ -407,6 +372,7 @@ let PostThreadItemLoaded = ({ record={record} richText={richText} onPressReply={onPressReply} + logContext="PostThreadItem" /> </View> </View> @@ -432,7 +398,7 @@ let PostThreadItemLoaded = ({ testID={`postThreadItem-by-${post.author.handle}`} href={postHref} style={[pal.view]} - moderation={moderation.content} + modui={moderation.ui('contentList')} iconSize={isThreadedChild ? 26 : 38} iconStyles={ isThreadedChild @@ -482,7 +448,8 @@ let PostThreadItemLoaded = ({ did={post.author.did} handle={post.author.handle} avatar={post.author.avatar} - moderation={moderation.avatar} + moderation={moderation.ui('avatar')} + type={post.author.associated?.labeler ? 'labeler' : 'user'} /> {showChildReplyLine && ( @@ -508,19 +475,21 @@ let PostThreadItemLoaded = ({ }> <PostMeta author={post.author} + moderation={moderation} authorHasWarning={!!post.author.labels?.length} timestamp={post.indexedAt} postHref={postHref} showAvatar={isThreadedChild} - avatarModeration={moderation.avatar} + avatarModeration={moderation.ui('avatar')} avatarSize={28} displayNameType="md-bold" displayNameStyle={isThreadedChild && s.ml2} style={isThreadedChild && s.mb2} /> + <LabelsOnMyPost post={post} /> <PostAlerts - moderation={moderation.content} - style={styles.alert} + modui={moderation.ui('contentList')} + style={[a.pt_xs, a.pb_sm]} /> {richText?.text ? ( <View style={styles.postTextContainer}> @@ -542,24 +511,16 @@ let PostThreadItemLoaded = ({ /> ) : undefined} {post.embed && ( - <ContentHider - style={styles.contentHider} - moderation={moderation.embed} - moderationDecisions={moderation.decisions} - ignoreMute={isEmbedByEmbedder(post.embed, post.author.did)} - ignoreQuoteDecisions> - <PostEmbeds - embed={post.embed} - moderation={moderation.embed} - moderationDecisions={moderation.decisions} - /> - </ContentHider> + <View style={[a.pb_xs]}> + <PostEmbeds embed={post.embed} moderation={moderation} /> + </View> )} <PostCtrls post={post} record={record} richText={richText} onPressReply={onPressReply} + logContext="PostThreadItem" /> </View> </View> @@ -577,7 +538,7 @@ let PostThreadItemLoaded = ({ title={itemTitle} noFeedback> <Text type="sm-medium" style={pal.textLight}> - More + <Trans>More</Trans> </Text> <FontAwesomeIcon icon="angle-right" @@ -620,7 +581,6 @@ function PostOuterWrapper({ return ( <View style={[ - pal.view, pal.border, styles.cursor, { @@ -648,7 +608,6 @@ function PostOuterWrapper({ <View style={[ styles.outer, - pal.view, pal.border, showParentReplyLine && hasPrecedingItem && styles.noTopBorder, styles.cursor, diff --git a/src/view/com/post/Post.tsx b/src/view/com/post/Post.tsx index 5fa4da84e..47e46eb0c 100644 --- a/src/view/com/post/Post.tsx +++ b/src/view/com/post/Post.tsx @@ -4,7 +4,7 @@ import { AppBskyFeedDefs, AppBskyFeedPost, AtUri, - PostModeration, + ModerationDecision, RichText as RichTextAPI, } from '@atproto/api' import {moderatePost_wrapped as moderatePost} from '#/lib/moderatePost_wrapped' @@ -14,8 +14,9 @@ import {UserInfoText} from '../util/UserInfoText' import {PostMeta} from '../util/PostMeta' import {PostEmbeds} from '../util/post-embeds' import {PostCtrls} from '../util/post-ctrls/PostCtrls' -import {ContentHider} from '../util/moderation/ContentHider' -import {PostAlerts} from '../util/moderation/PostAlerts' +import {ContentHider} from '../../../components/moderation/ContentHider' +import {PostAlerts} from '../../../components/moderation/PostAlerts' +import {LabelsOnMyPost} from '../../../components/moderation/LabelsOnMe' import {Text} from '../util/text/Text' import {RichText} from '#/components/RichText' import {PreviewableUserAvatar} from '../util/UserAvatar' @@ -93,7 +94,7 @@ function PostInner({ post: Shadow<AppBskyFeedDefs.PostView> record: AppBskyFeedPost.Record richText: RichTextAPI - moderation: PostModeration + moderation: ModerationDecision showReplyLine?: boolean style?: StyleProp<ViewStyle> }) { @@ -117,11 +118,7 @@ function PostInner({ uri: post.uri, cid: post.cid, text: record.text, - author: { - handle: post.author.handle, - displayName: post.author.displayName, - avatar: post.author.avatar, - }, + author: post.author, embed: post.embed, moderation, }, @@ -133,7 +130,7 @@ function PostInner({ }, [setLimitLines]) return ( - <Link href={itemHref} style={[styles.outer, pal.view, pal.border, style]}> + <Link href={itemHref} style={[styles.outer, pal.border, style]}> {showReplyLine && <View style={styles.replyLine} />} <View style={styles.layout}> <View style={styles.layoutAvi}> @@ -142,12 +139,14 @@ function PostInner({ did={post.author.did} handle={post.author.handle} avatar={post.author.avatar} - moderation={moderation.avatar} + moderation={moderation.ui('avatar')} + type={post.author.associated?.labeler ? 'labeler' : 'user'} /> </View> <View style={styles.layoutContent}> <PostMeta author={post.author} + moderation={moderation} authorHasWarning={!!post.author.labels?.length} timestamp={post.indexedAt} postHref={itemHref} @@ -176,11 +175,15 @@ function PostInner({ </Text> </View> )} + <LabelsOnMyPost post={post} /> <ContentHider - moderation={moderation.content} + modui={moderation.ui('contentView')} style={styles.contentHider} childContainerStyle={styles.contentHiderChild}> - <PostAlerts moderation={moderation.content} style={styles.alert} /> + <PostAlerts + modui={moderation.ui('contentView')} + style={[a.py_xs]} + /> {richText.text ? ( <View style={styles.postTextContainer}> <RichText @@ -202,17 +205,7 @@ function PostInner({ /> ) : undefined} {post.embed ? ( - <ContentHider - moderation={moderation.embed} - moderationDecisions={moderation.decisions} - ignoreQuoteDecisions - style={styles.contentHider}> - <PostEmbeds - embed={post.embed} - moderation={moderation.embed} - moderationDecisions={moderation.decisions} - /> - </ContentHider> + <PostEmbeds embed={post.embed} moderation={moderation} /> ) : null} </ContentHider> <PostCtrls @@ -220,6 +213,7 @@ function PostInner({ record={record} richText={richText} onPressReply={onPressReply} + logContext="Post" /> </View> </View> diff --git a/src/view/com/posts/Feed.tsx b/src/view/com/posts/Feed.tsx index cd3e98785..b86646a4d 100644 --- a/src/view/com/posts/Feed.tsx +++ b/src/view/com/posts/Feed.tsx @@ -33,6 +33,7 @@ import {useLingui} from '@lingui/react' import {DiscoverFallbackHeader} from './DiscoverFallbackHeader' import {FALLBACK_MARKER_POST} from '#/lib/api/feed/home' import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender' +import {logEvent} from '#/lib/statsig/statsig' const LOADING_ITEM = {_reactKey: '__loading__'} const EMPTY_FEED_ITEM = {_reactKey: '__empty__'} @@ -223,16 +224,29 @@ let Feed = ({ setIsPTRing(false) }, [refetch, track, setIsPTRing, onHasNew]) + const feedType = feed.split('|')[0] const onEndReached = React.useCallback(async () => { if (isFetching || !hasNextPage || isError) return + logEvent('feed:endReached', { + feedType: feedType, + itemCount: feedItems.length, + }) track('Feed:onEndReached') try { await fetchNextPage() } catch (err) { logger.error('Failed to load more posts', {message: err}) } - }, [isFetching, hasNextPage, isError, fetchNextPage, track]) + }, [ + isFetching, + hasNextPage, + isError, + fetchNextPage, + track, + feedType, + feedItems.length, + ]) const onPressTryAgain = React.useCallback(() => { refetch() diff --git a/src/view/com/posts/FeedErrorMessage.tsx b/src/view/com/posts/FeedErrorMessage.tsx index 6d99c32f1..c52090f97 100644 --- a/src/view/com/posts/FeedErrorMessage.tsx +++ b/src/view/com/posts/FeedErrorMessage.tsx @@ -9,13 +9,13 @@ import {usePalette} from 'lib/hooks/usePalette' import {useNavigation} from '@react-navigation/native' import {NavigationProp} from 'lib/routes/types' import {logger} from '#/logger' -import {useModalControls} from '#/state/modals' import {msg as msgLingui, Trans} from '@lingui/macro' import {useLingui} from '@lingui/react' import {FeedDescriptor} from '#/state/queries/post-feed' import {EmptyState} from '../util/EmptyState' import {cleanError} from '#/lib/strings/errors' import {useRemoveFeedMutation} from '#/state/queries/preferences' +import * as Prompt from '#/components/Prompt' export enum KnownError { Block = 'Block', @@ -118,35 +118,29 @@ function FeedgenErrorMessage({ ) const [_, uri] = feedDesc.split('|') const [ownerDid] = safeParseFeedgenUri(uri) - const {openModal, closeModal} = useModalControls() + const removePromptControl = Prompt.usePromptControl() const {mutateAsync: removeFeed} = useRemoveFeedMutation() const onViewProfile = React.useCallback(() => { navigation.navigate('Profile', {name: ownerDid}) }, [navigation, ownerDid]) + const onPressRemoveFeed = React.useCallback(() => { + removePromptControl.open() + }, [removePromptControl]) + const onRemoveFeed = React.useCallback(async () => { - openModal({ - name: 'confirm', - title: _l(msgLingui`Remove feed`), - message: _l(msgLingui`Remove this feed from your saved feeds?`), - async onPressConfirm() { - try { - await removeFeed({uri}) - } catch (err) { - Toast.show( - _l( - msgLingui`There was an an issue removing this feed. Please check your internet connection and try again.`, - ), - ) - logger.error('Failed to remove feed', {message: err}) - } - }, - onPressCancel() { - closeModal() - }, - }) - }, [openModal, closeModal, uri, removeFeed, _l]) + try { + await removeFeed({uri}) + } catch (err) { + Toast.show( + _l( + msgLingui`There was an an issue removing this feed. Please check your internet connection and try again.`, + ), + ) + logger.error('Failed to remove feed', {message: err}) + } + }, [uri, removeFeed, _l]) const cta = React.useMemo(() => { switch (knownError) { @@ -179,27 +173,38 @@ function FeedgenErrorMessage({ }, [knownError, onViewProfile, onRemoveFeed, _l]) return ( - <View - style={[ - pal.border, - pal.viewLight, - { - borderTopWidth: 1, - paddingHorizontal: 20, - paddingVertical: 18, - gap: 12, - }, - ]}> - <Text style={pal.text}>{msg}</Text> + <> + <View + style={[ + pal.border, + pal.viewLight, + { + borderTopWidth: 1, + paddingHorizontal: 20, + paddingVertical: 18, + gap: 12, + }, + ]}> + <Text style={pal.text}>{msg}</Text> - {rawError?.message && ( - <Text style={pal.textLight}> - <Trans>Message from server: {rawError.message}</Trans> - </Text> - )} + {rawError?.message && ( + <Text style={pal.textLight}> + <Trans>Message from server: {rawError.message}</Trans> + </Text> + )} - {cta} - </View> + {cta} + </View> + + <Prompt.Basic + control={removePromptControl} + title={_l(msgLingui`Remove feed?`)} + description={_l(msgLingui`Remove this feed from your saved feeds`)} + onConfirm={onPressRemoveFeed} + confirmButtonCta={_l(msgLingui`Remove`)} + confirmButtonColor="negative" + /> + </> ) } diff --git a/src/view/com/posts/FeedItem.tsx b/src/view/com/posts/FeedItem.tsx index 7d29703e2..0fbcc4a13 100644 --- a/src/view/com/posts/FeedItem.tsx +++ b/src/view/com/posts/FeedItem.tsx @@ -4,7 +4,7 @@ import { AppBskyFeedDefs, AppBskyFeedPost, AtUri, - PostModeration, + ModerationDecision, RichText as RichTextAPI, } from '@atproto/api' import { @@ -18,8 +18,9 @@ import {UserInfoText} from '../util/UserInfoText' import {PostMeta} from '../util/PostMeta' import {PostCtrls} from '../util/post-ctrls/PostCtrls' import {PostEmbeds} from '../util/post-embeds' -import {ContentHider} from '../util/moderation/ContentHider' -import {PostAlerts} from '../util/moderation/PostAlerts' +import {ContentHider} from '#/components/moderation/ContentHider' +import {PostAlerts} from '../../../components/moderation/PostAlerts' +import {LabelsOnMyPost} from '../../../components/moderation/LabelsOnMe' import {RichText} from '#/components/RichText' import {PreviewableUserAvatar} from '../util/UserAvatar' import {s} from 'lib/styles' @@ -27,13 +28,11 @@ import {usePalette} from 'lib/hooks/usePalette' import {sanitizeDisplayName} from 'lib/strings/display-names' import {sanitizeHandle} from 'lib/strings/handles' import {makeProfileLink} from 'lib/routes/links' -import {isEmbedByEmbedder} from 'lib/embeds' import {MAX_POST_LINES} from 'lib/constants' import {countLines} from 'lib/strings/helpers' import {useComposerControls} from '#/state/shell/composer' import {Shadow, usePostShadow, POST_TOMBSTONE} from '#/state/cache/post-shadow' import {FeedNameText} from '../util/FeedInfoText' -import {useSession} from '#/state/session' import {Trans, msg} from '@lingui/macro' import {useLingui} from '@lingui/react' import {atoms as a} from '#/alf' @@ -50,7 +49,7 @@ export function FeedItem({ post: AppBskyFeedDefs.PostView record: AppBskyFeedPost.Record reason: AppBskyFeedDefs.ReasonRepost | ReasonFeedSource | undefined - moderation: PostModeration + moderation: ModerationDecision isThreadChild?: boolean isThreadLastChild?: boolean isThreadParent?: boolean @@ -100,7 +99,7 @@ let FeedItemInner = ({ record: AppBskyFeedPost.Record reason: AppBskyFeedDefs.ReasonRepost | ReasonFeedSource | undefined richText: RichTextAPI - moderation: PostModeration + moderation: ModerationDecision isThreadChild?: boolean isThreadLastChild?: boolean isThreadParent?: boolean @@ -108,14 +107,10 @@ let FeedItemInner = ({ const {openComposer} = useComposerControls() const pal = usePalette('default') const {_} = useLingui() - const {currentAccount} = useSession() const href = useMemo(() => { const urip = new AtUri(post.uri) return makeProfileLink(post.author, 'post', urip.rkey) }, [post.uri, post.author]) - const isModeratedPost = - moderation.decisions.post.cause?.type === 'label' && - moderation.decisions.post.cause.label.src !== currentAccount?.did const replyAuthorDid = useMemo(() => { if (!record?.reply) { @@ -131,11 +126,7 @@ let FeedItemInner = ({ uri: post.uri, cid: post.cid, text: record.text || '', - author: { - handle: post.author.handle, - displayName: post.author.displayName, - avatar: post.author.avatar, - }, + author: post.author, embed: post.embed, moderation, }, @@ -144,12 +135,11 @@ let FeedItemInner = ({ const outerStyles = [ styles.outer, - pal.view, { borderColor: pal.colors.border, paddingBottom: isThreadLastChild || (!isThreadChild && !isThreadParent) - ? 6 + ? 8 : undefined, }, isThreadChild ? styles.outerSmallTop : undefined, @@ -230,6 +220,7 @@ let FeedItemInner = ({ numberOfLines={1} text={sanitizeDisplayName( reason.by.displayName || sanitizeHandle(reason.by.handle), + moderation.ui('displayName'), )} href={makeProfileLink(reason.by)} /> @@ -247,7 +238,8 @@ let FeedItemInner = ({ did={post.author.did} handle={post.author.handle} avatar={post.author.avatar} - moderation={moderation.avatar} + moderation={moderation.ui('avatar')} + type={post.author.associated?.labeler ? 'labeler' : 'user'} /> {isThreadParent && ( <View @@ -265,6 +257,7 @@ let FeedItemInner = ({ <View style={styles.layoutContent}> <PostMeta author={post.author} + moderation={moderation} authorHasWarning={!!post.author.labels?.length} timestamp={post.indexedAt} postHref={href} @@ -296,6 +289,7 @@ let FeedItemInner = ({ </Text> </View> )} + <LabelsOnMyPost post={post} /> <PostContent moderation={moderation} richText={richText} @@ -307,9 +301,7 @@ let FeedItemInner = ({ record={record} richText={richText} onPressReply={onPressReply} - showAppealLabelItem={ - post.author.did === currentAccount?.did && isModeratedPost - } + logContext="FeedItem" /> </View> </View> @@ -324,7 +316,7 @@ let PostContent = ({ postEmbed, postAuthor, }: { - moderation: PostModeration + moderation: ModerationDecision richText: RichTextAPI postEmbed: AppBskyFeedDefs.PostView['embed'] postAuthor: AppBskyFeedDefs.PostView['author'] @@ -342,10 +334,10 @@ let PostContent = ({ return ( <ContentHider testID="contentHider-post" - moderation={moderation.content} + modui={moderation.ui('contentList')} ignoreMute childContainerStyle={styles.contentHiderChild}> - <PostAlerts moderation={moderation.content} style={styles.alert} /> + <PostAlerts modui={moderation.ui('contentList')} style={[a.py_xs]} /> {richText.text ? ( <View style={styles.postTextContainer}> <RichText @@ -367,19 +359,9 @@ let PostContent = ({ /> ) : undefined} {postEmbed ? ( - <ContentHider - testID="contentHider-embed" - moderation={moderation.embed} - moderationDecisions={moderation.decisions} - ignoreMute={isEmbedByEmbedder(postEmbed, postAuthor.did)} - ignoreQuoteDecisions - style={styles.embed}> - <PostEmbeds - embed={postEmbed} - moderation={moderation.embed} - moderationDecisions={moderation.decisions} - /> - </ContentHider> + <View style={[a.pb_sm]}> + <PostEmbeds embed={postEmbed} moderation={moderation} /> + </View> ) : null} </ContentHider> ) diff --git a/src/view/com/posts/FeedSlice.tsx b/src/view/com/posts/FeedSlice.tsx index 84edee4a1..49e48aa20 100644 --- a/src/view/com/posts/FeedSlice.tsx +++ b/src/view/com/posts/FeedSlice.tsx @@ -78,11 +78,7 @@ function ViewFullThread({slice}: {slice: FeedPostSlice}) { }, [slice.rootUri]) return ( - <Link - style={[pal.view, styles.viewFullThread]} - href={itemHref} - asAnchor - noFeedback> + <Link style={[styles.viewFullThread]} href={itemHref} asAnchor noFeedback> <View style={styles.viewFullThreadDots}> <Svg width="4" height="40"> <Line diff --git a/src/view/com/profile/FollowButton.tsx b/src/view/com/profile/FollowButton.tsx index 9cc635b66..7b090ffeb 100644 --- a/src/view/com/profile/FollowButton.tsx +++ b/src/view/com/profile/FollowButton.tsx @@ -13,13 +13,18 @@ export function FollowButton({ followedType = 'default', profile, labelStyle, + logContext, }: { unfollowedType?: ButtonType followedType?: ButtonType profile: Shadow<AppBskyActorDefs.ProfileViewBasic> labelStyle?: StyleProp<TextStyle> + logContext: 'ProfileCard' }) { - const [queueFollow, queueUnfollow] = useProfileFollowMutationQueue(profile) + const [queueFollow, queueUnfollow] = useProfileFollowMutationQueue( + profile, + logContext, + ) const {_} = useLingui() const onPressFollow = async () => { diff --git a/src/view/com/profile/ProfileCard.tsx b/src/view/com/profile/ProfileCard.tsx index 266adc51d..235139fff 100644 --- a/src/view/com/profile/ProfileCard.tsx +++ b/src/view/com/profile/ProfileCard.tsx @@ -3,7 +3,8 @@ import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native' import { AppBskyActorDefs, moderateProfile, - ProfileModeration, + ModerationCause, + ModerationDecision, } from '@atproto/api' import {Link} from '../util/Link' import {Text} from '../util/text/Text' @@ -14,16 +15,13 @@ import {FollowButton} from './FollowButton' import {sanitizeDisplayName} from 'lib/strings/display-names' import {sanitizeHandle} from 'lib/strings/handles' import {makeProfileLink} from 'lib/routes/links' -import { - describeModerationCause, - getProfileModerationCauses, - getModerationCauseKey, -} from 'lib/moderation' +import {getModerationCauseKey, isJustAMute} from 'lib/moderation' import {Shadow} from '#/state/cache/types' import {useModerationOpts} from '#/state/queries/preferences' import {useProfileShadow} from '#/state/cache/profile-shadow' import {useSession} from '#/state/session' import {Trans} from '@lingui/macro' +import {useModerationCauseDescription} from '#/lib/moderation/useModerationCauseDescription' export function ProfileCard({ testID, @@ -33,6 +31,7 @@ export function ProfileCard({ noBorder, followers, renderButton, + onPress, style, }: { testID?: string @@ -44,20 +43,19 @@ export function ProfileCard({ renderButton?: ( profile: Shadow<AppBskyActorDefs.ProfileViewBasic>, ) => React.ReactNode + onPress?: () => void style?: StyleProp<ViewStyle> }) { const pal = usePalette('default') const profile = useProfileShadow(profileUnshadowed) const moderationOpts = useModerationOpts() + const isLabeler = profile?.associated?.labeler if (!moderationOpts) { return null } const moderation = moderateProfile(profile, moderationOpts) - if ( - !noModFilter && - moderation.account.filter && - moderation.account.cause?.type !== 'muted' - ) { + const modui = moderation.ui('profileList') + if (!noModFilter && modui.filter && !isJustAMute(modui)) { return null } @@ -73,6 +71,7 @@ export function ProfileCard({ ]} href={makeProfileLink(profile)} title={profile.handle} + onBeforePress={onPress} asAnchor anchorNoUnderline> <View style={styles.layout}> @@ -80,7 +79,8 @@ export function ProfileCard({ <UserAvatar size={40} avatar={profile.avatar} - moderation={moderation.avatar} + moderation={moderation.ui('avatar')} + type={isLabeler ? 'labeler' : 'user'} /> </View> <View style={styles.layoutContent}> @@ -91,7 +91,7 @@ export function ProfileCard({ lineHeight={1.2}> {sanitizeDisplayName( profile.displayName || sanitizeHandle(profile.handle), - moderation.profile, + moderation.ui('displayName'), )} </Text> <Text type="md" style={[pal.textLight]} numberOfLines={1}> @@ -103,7 +103,7 @@ export function ProfileCard({ /> {!!profile.viewer?.followedBy && <View style={s.flexRow} />} </View> - {renderButton ? ( + {renderButton && !isLabeler ? ( <View style={styles.layoutButton}>{renderButton(profile)}</View> ) : undefined} </View> @@ -119,17 +119,17 @@ export function ProfileCard({ ) } -function ProfileCardPills({ +export function ProfileCardPills({ followedBy, moderation, }: { followedBy: boolean - moderation: ProfileModeration + moderation: ModerationDecision }) { const pal = usePalette('default') - const causes = getProfileModerationCauses(moderation) - if (!followedBy && !causes.length) { + const modui = moderation.ui('profileList') + if (!followedBy && !modui.inform && !modui.alert) { return null } @@ -142,19 +142,41 @@ function ProfileCardPills({ </Text> </View> )} - {causes.map(cause => { - const desc = describeModerationCause(cause, 'account') - return ( - <View - style={[s.mt5, pal.btn, styles.pill]} - key={getModerationCauseKey(cause)}> - <Text type="xs" style={pal.text}> - {cause?.type === 'label' ? 'âš ' : ''} - {desc.name} - </Text> - </View> - ) - })} + {modui.alerts.map(alert => ( + <ProfileCardPillModerationCause + key={getModerationCauseKey(alert)} + cause={alert} + severity="alert" + /> + ))} + {modui.informs.map(inform => ( + <ProfileCardPillModerationCause + key={getModerationCauseKey(inform)} + cause={inform} + severity="inform" + /> + ))} + </View> + ) +} + +function ProfileCardPillModerationCause({ + cause, + severity, +}: { + cause: ModerationCause + severity: 'alert' | 'inform' +}) { + const pal = usePalette('default') + const {name} = useModerationCauseDescription(cause) + return ( + <View + style={[s.mt5, pal.btn, styles.pill]} + key={getModerationCauseKey(cause)}> + <Text type="xs" style={pal.text}> + {severity === 'alert' ? 'âš ' : ''} + {name} + </Text> </View> ) } @@ -177,7 +199,7 @@ function FollowersList({ f, mod: moderateProfile(f, moderationOpts), })) - .filter(({mod}) => !mod.account.filter) + .filter(({mod}) => !mod.ui('profileList').filter) }, [followers, moderationOpts]) if (!followersWithMods?.length) { @@ -199,7 +221,12 @@ function FollowersList({ {followersWithMods.slice(0, 3).map(({f, mod}) => ( <View key={f.did} style={styles.followedByAviContainer}> <View style={[styles.followedByAvi, pal.view]}> - <UserAvatar avatar={f.avatar} size={32} moderation={mod.avatar} /> + <UserAvatar + avatar={f.avatar} + size={32} + moderation={mod.ui('avatar')} + type={f.associated?.labeler ? 'labeler' : 'user'} + /> </View> </View> ))} @@ -212,11 +239,13 @@ export function ProfileCardWithFollowBtn({ noBg, noBorder, followers, + onPress, }: { profile: AppBskyActorDefs.ProfileViewBasic noBg?: boolean noBorder?: boolean followers?: AppBskyActorDefs.ProfileView[] | undefined + onPress?: () => void }) { const {currentAccount} = useSession() const isMe = profile.did === currentAccount?.did @@ -230,8 +259,11 @@ export function ProfileCardWithFollowBtn({ renderButton={ isMe ? undefined - : profileShadow => <FollowButton profile={profileShadow} /> + : profileShadow => ( + <FollowButton profile={profileShadow} logContext="ProfileCard" /> + ) } + onPress={onPress} /> ) } diff --git a/src/view/com/profile/ProfileFollowers.tsx b/src/view/com/profile/ProfileFollowers.tsx index 411ae6c17..b11a33f27 100644 --- a/src/view/com/profile/ProfileFollowers.tsx +++ b/src/view/com/profile/ProfileFollowers.tsx @@ -1,39 +1,66 @@ import React from 'react' -import {ActivityIndicator, StyleSheet, View} from 'react-native' import {AppBskyActorDefs as ActorDefs} from '@atproto/api' -import {CenteredView} from '../util/Views' -import {LoadingScreen} from '../util/LoadingScreen' import {List} from '../util/List' -import {ErrorMessage} from '../util/error/ErrorMessage' import {ProfileCardWithFollowBtn} from './ProfileCard' import {useProfileFollowersQuery} from '#/state/queries/profile-followers' import {useResolveDidQuery} from '#/state/queries/resolve-uri' import {logger} from '#/logger' import {cleanError} from '#/lib/strings/errors' +import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender' +import { + ListFooter, + ListHeaderDesktop, + ListMaybePlaceholder, +} from '#/components/Lists' +import {msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {useSession} from 'state/session' +import {View} from 'react-native' + +function renderItem({item}: {item: ActorDefs.ProfileViewBasic}) { + return <ProfileCardWithFollowBtn key={item.did} profile={item} /> +} + +function keyExtractor(item: ActorDefs.ProfileViewBasic) { + return item.did +} export function ProfileFollowers({name}: {name: string}) { + const {_} = useLingui() + const initialNumToRender = useInitialNumToRender() + const {currentAccount} = useSession() + const [isPTRing, setIsPTRing] = React.useState(false) const { data: resolvedDid, + isLoading: isDidLoading, error: resolveError, - isFetching: isFetchingDid, } = useResolveDidQuery(name) const { data, + isLoading: isFollowersLoading, isFetching, - isFetched, isFetchingNextPage, hasNextPage, fetchNextPage, - isError, error, refetch, } = useProfileFollowersQuery(resolvedDid) + const isError = React.useMemo( + () => !!resolveError || !!error, + [resolveError, error], + ) + + const isMe = React.useMemo(() => { + return resolvedDid === currentAccount?.did + }, [resolvedDid, currentAccount?.did]) + const followers = React.useMemo(() => { if (data?.pages) { return data.pages.flatMap(page => page.followers) } + return [] }, [data]) const onRefresh = React.useCallback(async () => { @@ -47,7 +74,7 @@ export function ProfileFollowers({name}: {name: string}) { }, [refetch, setIsPTRing]) const onEndReached = async () => { - if (isFetching || !hasNextPage || isError) return + if (isFetching || !hasNextPage || !!error) return try { await fetchNextPage() } catch (err) { @@ -55,57 +82,38 @@ export function ProfileFollowers({name}: {name: string}) { } } - const renderItem = React.useCallback( - ({item}: {item: ActorDefs.ProfileViewBasic}) => ( - <ProfileCardWithFollowBtn key={item.did} profile={item} /> - ), - [], - ) - - if (isFetchingDid || !isFetched) { - return <LoadingScreen /> - } - - // error - // = - if (resolveError || isError) { - return ( - <CenteredView> - <ErrorMessage - message={cleanError(resolveError || error)} - onPressTryAgain={onRefresh} - /> - </CenteredView> - ) - } - - // loaded - // = return ( - <List - data={followers} - keyExtractor={item => item.did} - refreshing={isPTRing} - onRefresh={onRefresh} - onEndReached={onEndReached} - renderItem={renderItem} - initialNumToRender={15} - // FIXME(dan) - // eslint-disable-next-line react/no-unstable-nested-components - ListFooterComponent={() => ( - <View style={styles.footer}> - {(isFetching || isFetchingNextPage) && <ActivityIndicator />} - </View> + <View style={{flex: 1}}> + <ListMaybePlaceholder + isLoading={isDidLoading || isFollowersLoading} + isEmpty={followers.length < 1} + isError={isError} + emptyType="results" + emptyMessage={ + isMe + ? _(msg`You do not have any followers.`) + : _(msg`This user doesn't have any followers.`) + } + errorMessage={cleanError(resolveError || error)} + onRetry={isError ? refetch : undefined} + /> + {followers.length > 0 && ( + <List + data={followers} + renderItem={renderItem} + keyExtractor={keyExtractor} + refreshing={isPTRing} + onRefresh={onRefresh} + onEndReached={onEndReached} + onEndReachedThreshold={4} + ListHeaderComponent={<ListHeaderDesktop title={_(msg`Followers`)} />} + ListFooterComponent={<ListFooter isFetching={isFetchingNextPage} />} + // @ts-ignore our .web version only -prf + desktopFixedHeight + initialNumToRender={initialNumToRender} + windowSize={11} + /> )} - // @ts-ignore our .web version only -prf - desktopFixedHeight - /> + </View> ) } - -const styles = StyleSheet.create({ - footer: { - height: 200, - paddingTop: 20, - }, -}) diff --git a/src/view/com/profile/ProfileFollows.tsx b/src/view/com/profile/ProfileFollows.tsx index bd4af1081..d99e2b840 100644 --- a/src/view/com/profile/ProfileFollows.tsx +++ b/src/view/com/profile/ProfileFollows.tsx @@ -1,39 +1,65 @@ import React from 'react' -import {ActivityIndicator, StyleSheet, View} from 'react-native' import {AppBskyActorDefs as ActorDefs} from '@atproto/api' -import {CenteredView} from '../util/Views' -import {LoadingScreen} from '../util/LoadingScreen' import {List} from '../util/List' -import {ErrorMessage} from '../util/error/ErrorMessage' import {ProfileCardWithFollowBtn} from './ProfileCard' import {useProfileFollowsQuery} from '#/state/queries/profile-follows' import {useResolveDidQuery} from '#/state/queries/resolve-uri' import {logger} from '#/logger' import {cleanError} from '#/lib/strings/errors' +import { + ListFooter, + ListHeaderDesktop, + ListMaybePlaceholder, +} from '#/components/Lists' +import {useInitialNumToRender} from 'lib/hooks/useInitialNumToRender' +import {useSession} from 'state/session' +import {msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' + +function renderItem({item}: {item: ActorDefs.ProfileViewBasic}) { + return <ProfileCardWithFollowBtn key={item.did} profile={item} /> +} + +function keyExtractor(item: ActorDefs.ProfileViewBasic) { + return item.did +} export function ProfileFollows({name}: {name: string}) { + const {_} = useLingui() + const initialNumToRender = useInitialNumToRender() + const {currentAccount} = useSession() + const [isPTRing, setIsPTRing] = React.useState(false) const { data: resolvedDid, + isLoading: isDidLoading, error: resolveError, - isFetching: isFetchingDid, } = useResolveDidQuery(name) const { data, + isLoading: isFollowsLoading, isFetching, - isFetched, isFetchingNextPage, hasNextPage, fetchNextPage, - isError, error, refetch, } = useProfileFollowsQuery(resolvedDid) + const isError = React.useMemo( + () => !!resolveError || !!error, + [resolveError, error], + ) + + const isMe = React.useMemo(() => { + return resolvedDid === currentAccount?.did + }, [resolvedDid, currentAccount?.did]) + const follows = React.useMemo(() => { if (data?.pages) { return data.pages.flatMap(page => page.follows) } + return [] }, [data]) const onRefresh = React.useCallback(async () => { @@ -47,7 +73,7 @@ export function ProfileFollows({name}: {name: string}) { }, [refetch, setIsPTRing]) const onEndReached = async () => { - if (isFetching || !hasNextPage || isError) return + if (isFetching || !hasNextPage || !!error) return try { await fetchNextPage() } catch (err) { @@ -55,57 +81,38 @@ export function ProfileFollows({name}: {name: string}) { } } - const renderItem = React.useCallback( - ({item}: {item: ActorDefs.ProfileViewBasic}) => ( - <ProfileCardWithFollowBtn key={item.did} profile={item} /> - ), - [], - ) - - if (isFetchingDid || !isFetched) { - return <LoadingScreen /> - } - - // error - // = - if (resolveError || isError) { - return ( - <CenteredView> - <ErrorMessage - message={cleanError(resolveError || error)} - onPressTryAgain={onRefresh} - /> - </CenteredView> - ) - } - - // loaded - // = return ( - <List - data={follows} - keyExtractor={item => item.did} - refreshing={isPTRing} - onRefresh={onRefresh} - onEndReached={onEndReached} - renderItem={renderItem} - initialNumToRender={15} - // FIXME(dan) - // eslint-disable-next-line react/no-unstable-nested-components - ListFooterComponent={() => ( - <View style={styles.footer}> - {(isFetching || isFetchingNextPage) && <ActivityIndicator />} - </View> + <> + <ListMaybePlaceholder + isLoading={isDidLoading || isFollowsLoading} + isEmpty={follows.length < 1} + isError={isError} + emptyType="results" + emptyMessage={ + isMe + ? _(msg`You are not following anyone.`) + : _(msg`This user isn't following anyone.`) + } + errorMessage={cleanError(resolveError || error)} + onRetry={isError ? refetch : undefined} + /> + {follows.length > 0 && ( + <List + data={follows} + renderItem={renderItem} + keyExtractor={keyExtractor} + refreshing={isPTRing} + onRefresh={onRefresh} + onEndReached={onEndReached} + onEndReachedThreshold={4} + ListHeaderComponent={<ListHeaderDesktop title={_(msg`Following`)} />} + ListFooterComponent={<ListFooter isFetching={isFetchingNextPage} />} + // @ts-ignore our .web version only -prf + desktopFixedHeight + initialNumToRender={initialNumToRender} + windowSize={11} + /> )} - // @ts-ignore our .web version only -prf - desktopFixedHeight - /> + </> ) } - -const styles = StyleSheet.create({ - footer: { - height: 200, - paddingTop: 20, - }, -}) diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx deleted file mode 100644 index 3e479d7b5..000000000 --- a/src/view/com/profile/ProfileHeader.tsx +++ /dev/null @@ -1,785 +0,0 @@ -import React, {memo, useMemo} from 'react' -import { - StyleSheet, - TouchableOpacity, - TouchableWithoutFeedback, - View, -} from 'react-native' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' -import {useNavigation} from '@react-navigation/native' -import {useQueryClient} from '@tanstack/react-query' -import { - AppBskyActorDefs, - ModerationOpts, - moderateProfile, - RichText as RichTextAPI, -} from '@atproto/api' -import {Trans, msg} from '@lingui/macro' -import {useLingui} from '@lingui/react' -import {NavigationProp} from 'lib/routes/types' -import {isNative, isWeb} from 'platform/detection' -import {BlurView} from '../util/BlurView' -import * as Toast from '../util/Toast' -import {LoadingPlaceholder} from '../util/LoadingPlaceholder' -import {Text} from '../util/text/Text' -import {ThemedText} from '../util/text/ThemedText' -import {RichText} from '#/components/RichText' -import {UserAvatar} from '../util/UserAvatar' -import {UserBanner} from '../util/UserBanner' -import {ProfileHeaderAlerts} from '../util/moderation/ProfileHeaderAlerts' -import {formatCount} from '../util/numeric/format' -import {NativeDropdown, DropdownItem} from '../util/forms/NativeDropdown' -import {Link} from '../util/Link' -import {ProfileHeaderSuggestedFollows} from './ProfileHeaderSuggestedFollows' -import {useModalControls} from '#/state/modals' -import {useLightboxControls, ProfileImageLightbox} from '#/state/lightbox' -import { - RQKEY as profileQueryKey, - useProfileMuteMutationQueue, - useProfileBlockMutationQueue, - useProfileFollowMutationQueue, -} from '#/state/queries/profile' -import {usePalette} from 'lib/hooks/usePalette' -import {useAnalytics} from 'lib/analytics/analytics' -import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' -import {BACK_HITSLOP} from 'lib/constants' -import {isInvalidHandle, sanitizeHandle} from 'lib/strings/handles' -import {makeProfileLink} from 'lib/routes/links' -import {pluralize} from 'lib/strings/helpers' -import {toShareUrl} from 'lib/strings/url-helpers' -import {sanitizeDisplayName} from 'lib/strings/display-names' -import {shareUrl} from 'lib/sharing' -import {s, colors} from 'lib/styles' -import {logger} from '#/logger' -import {useSession} from '#/state/session' -import {Shadow} from '#/state/cache/types' -import {useRequireAuth} from '#/state/session' -import {LabelInfo} from '../util/moderation/LabelInfo' -import {useProfileShadow} from 'state/cache/profile-shadow' -import {atoms as a} from '#/alf' - -let ProfileHeaderLoading = (_props: {}): React.ReactNode => { - const pal = usePalette('default') - return ( - <View style={pal.view}> - <LoadingPlaceholder width="100%" height={150} style={{borderRadius: 0}} /> - <View - style={[pal.view, {borderColor: pal.colors.background}, styles.avi]}> - <LoadingPlaceholder width={80} height={80} style={styles.br40} /> - </View> - <View style={styles.content}> - <View style={[styles.buttonsLine]}> - <LoadingPlaceholder width={167} height={31} style={styles.br50} /> - </View> - </View> - </View> - ) -} -ProfileHeaderLoading = memo(ProfileHeaderLoading) -export {ProfileHeaderLoading} - -interface Props { - profile: AppBskyActorDefs.ProfileViewDetailed - descriptionRT: RichTextAPI | null - moderationOpts: ModerationOpts - hideBackButton?: boolean - isPlaceholderProfile?: boolean -} - -let ProfileHeader = ({ - profile: profileUnshadowed, - descriptionRT, - moderationOpts, - hideBackButton = false, - isPlaceholderProfile, -}: Props): React.ReactNode => { - const profile: Shadow<AppBskyActorDefs.ProfileViewDetailed> = - useProfileShadow(profileUnshadowed) - const pal = usePalette('default') - const palInverted = usePalette('inverted') - const {currentAccount, hasSession} = useSession() - const requireAuth = useRequireAuth() - const {_} = useLingui() - const {openModal} = useModalControls() - const {openLightbox} = useLightboxControls() - const navigation = useNavigation<NavigationProp>() - const {track} = useAnalytics() - const invalidHandle = isInvalidHandle(profile.handle) - const {isDesktop} = useWebMediaQueries() - const [showSuggestedFollows, setShowSuggestedFollows] = React.useState(false) - const [queueFollow, queueUnfollow] = useProfileFollowMutationQueue(profile) - const [queueMute, queueUnmute] = useProfileMuteMutationQueue(profile) - const [queueBlock, queueUnblock] = useProfileBlockMutationQueue(profile) - const queryClient = useQueryClient() - const moderation = useMemo( - () => moderateProfile(profile, moderationOpts), - [profile, moderationOpts], - ) - - const invalidateProfileQuery = React.useCallback(() => { - queryClient.invalidateQueries({ - queryKey: profileQueryKey(profile.did), - }) - }, [queryClient, profile.did]) - - const onPressBack = React.useCallback(() => { - if (navigation.canGoBack()) { - navigation.goBack() - } else { - navigation.navigate('Home') - } - }, [navigation]) - - const onPressAvi = React.useCallback(() => { - if ( - profile.avatar && - !(moderation.avatar.blur && moderation.avatar.noOverride) - ) { - openLightbox(new ProfileImageLightbox(profile)) - } - }, [openLightbox, profile, moderation]) - - const onPressFollow = () => { - requireAuth(async () => { - try { - track('ProfileHeader:FollowButtonClicked') - await queueFollow() - Toast.show( - _( - msg`Following ${sanitizeDisplayName( - profile.displayName || profile.handle, - )}`, - ), - ) - } catch (e: any) { - if (e?.name !== 'AbortError') { - logger.error('Failed to follow', {message: String(e)}) - Toast.show(_(msg`There was an issue! ${e.toString()}`)) - } - } - }) - } - - const onPressUnfollow = () => { - requireAuth(async () => { - try { - track('ProfileHeader:UnfollowButtonClicked') - await queueUnfollow() - Toast.show( - _( - msg`No longer following ${sanitizeDisplayName( - profile.displayName || profile.handle, - )}`, - ), - ) - } catch (e: any) { - if (e?.name !== 'AbortError') { - logger.error('Failed to unfollow', {message: String(e)}) - Toast.show(_(msg`There was an issue! ${e.toString()}`)) - } - } - }) - } - - const onPressEditProfile = React.useCallback(() => { - track('ProfileHeader:EditProfileButtonClicked') - openModal({ - name: 'edit-profile', - profile, - }) - }, [track, openModal, profile]) - - const onPressShare = React.useCallback(() => { - track('ProfileHeader:ShareButtonClicked') - shareUrl(toShareUrl(makeProfileLink(profile))) - }, [track, profile]) - - const onPressAddRemoveLists = React.useCallback(() => { - track('ProfileHeader:AddToListsButtonClicked') - openModal({ - name: 'user-add-remove-lists', - subject: profile.did, - handle: profile.handle, - displayName: profile.displayName || profile.handle, - onAdd: invalidateProfileQuery, - onRemove: invalidateProfileQuery, - }) - }, [track, profile, openModal, invalidateProfileQuery]) - - const onPressMuteAccount = React.useCallback(async () => { - track('ProfileHeader:MuteAccountButtonClicked') - try { - await queueMute() - Toast.show(_(msg`Account muted`)) - } catch (e: any) { - if (e?.name !== 'AbortError') { - logger.error('Failed to mute account', {message: e}) - Toast.show(_(msg`There was an issue! ${e.toString()}`)) - } - } - }, [track, queueMute, _]) - - const onPressUnmuteAccount = React.useCallback(async () => { - track('ProfileHeader:UnmuteAccountButtonClicked') - try { - await queueUnmute() - Toast.show(_(msg`Account unmuted`)) - } catch (e: any) { - if (e?.name !== 'AbortError') { - logger.error('Failed to unmute account', {message: e}) - Toast.show(_(msg`There was an issue! ${e.toString()}`)) - } - } - }, [track, queueUnmute, _]) - - const onPressBlockAccount = React.useCallback(async () => { - track('ProfileHeader:BlockAccountButtonClicked') - openModal({ - name: 'confirm', - title: _(msg`Block Account`), - message: _( - msg`Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you.`, - ), - onPressConfirm: async () => { - try { - await queueBlock() - Toast.show(_(msg`Account blocked`)) - } catch (e: any) { - if (e?.name !== 'AbortError') { - logger.error('Failed to block account', {message: e}) - Toast.show(_(msg`There was an issue! ${e.toString()}`)) - } - } - }, - }) - }, [track, queueBlock, openModal, _]) - - const onPressUnblockAccount = React.useCallback(async () => { - track('ProfileHeader:UnblockAccountButtonClicked') - openModal({ - name: 'confirm', - title: _(msg`Unblock Account`), - message: _( - msg`The account will be able to interact with you after unblocking.`, - ), - onPressConfirm: async () => { - try { - await queueUnblock() - Toast.show(_(msg`Account unblocked`)) - } catch (e: any) { - if (e?.name !== 'AbortError') { - logger.error('Failed to unblock account', {message: e}) - Toast.show(_(msg`There was an issue! ${e.toString()}`)) - } - } - }, - }) - }, [track, queueUnblock, openModal, _]) - - const onPressReportAccount = React.useCallback(() => { - track('ProfileHeader:ReportAccountButtonClicked') - openModal({ - name: 'report', - did: profile.did, - }) - }, [track, openModal, profile]) - - const isMe = React.useMemo( - () => currentAccount?.did === profile.did, - [currentAccount, profile], - ) - const dropdownItems: DropdownItem[] = React.useMemo(() => { - let items: DropdownItem[] = [ - { - testID: 'profileHeaderDropdownShareBtn', - label: isWeb ? _(msg`Copy link to profile`) : _(msg`Share`), - onPress: onPressShare, - icon: { - ios: { - name: 'square.and.arrow.up', - }, - android: 'ic_menu_share', - web: 'share', - }, - }, - ] - if (hasSession) { - items.push({label: 'separator'}) - items.push({ - testID: 'profileHeaderDropdownListAddRemoveBtn', - label: _(msg`Add to Lists`), - onPress: onPressAddRemoveLists, - icon: { - ios: { - name: 'list.bullet', - }, - android: 'ic_menu_add', - web: 'list', - }, - }) - if (!isMe) { - if (!profile.viewer?.blocking) { - if (!profile.viewer?.mutedByList) { - items.push({ - testID: 'profileHeaderDropdownMuteBtn', - label: profile.viewer?.muted - ? _(msg`Unmute Account`) - : _(msg`Mute Account`), - onPress: profile.viewer?.muted - ? onPressUnmuteAccount - : onPressMuteAccount, - icon: { - ios: { - name: 'speaker.slash', - }, - android: 'ic_lock_silent_mode', - web: 'comment-slash', - }, - }) - } - } - if (!profile.viewer?.blockingByList) { - items.push({ - testID: 'profileHeaderDropdownBlockBtn', - label: profile.viewer?.blocking - ? _(msg`Unblock Account`) - : _(msg`Block Account`), - onPress: profile.viewer?.blocking - ? onPressUnblockAccount - : onPressBlockAccount, - icon: { - ios: { - name: 'person.fill.xmark', - }, - android: 'ic_menu_close_clear_cancel', - web: 'user-slash', - }, - }) - } - items.push({ - testID: 'profileHeaderDropdownReportBtn', - label: _(msg`Report Account`), - onPress: onPressReportAccount, - icon: { - ios: { - name: 'exclamationmark.triangle', - }, - android: 'ic_menu_report_image', - web: 'circle-exclamation', - }, - }) - } - } - return items - }, [ - isMe, - hasSession, - profile.viewer?.muted, - profile.viewer?.mutedByList, - profile.viewer?.blocking, - profile.viewer?.blockingByList, - onPressShare, - onPressUnmuteAccount, - onPressMuteAccount, - onPressUnblockAccount, - onPressBlockAccount, - onPressReportAccount, - onPressAddRemoveLists, - _, - ]) - - const blockHide = - !isMe && (profile.viewer?.blocking || profile.viewer?.blockedBy) - const following = formatCount(profile.followsCount || 0) - const followers = formatCount(profile.followersCount || 0) - const pluralizedFollowers = pluralize(profile.followersCount || 0, 'follower') - - return ( - <View style={[pal.view]} pointerEvents="box-none"> - <View pointerEvents="none"> - {isPlaceholderProfile ? ( - <LoadingPlaceholder - width="100%" - height={150} - style={{borderRadius: 0}} - /> - ) : ( - <UserBanner banner={profile.banner} moderation={moderation.avatar} /> - )} - </View> - <View style={styles.content} pointerEvents="box-none"> - <View style={[styles.buttonsLine]} pointerEvents="box-none"> - {isMe ? ( - <TouchableOpacity - testID="profileHeaderEditProfileButton" - onPress={onPressEditProfile} - style={[styles.btn, styles.mainBtn, pal.btn]} - accessibilityRole="button" - accessibilityLabel={_(msg`Edit profile`)} - accessibilityHint={_( - msg`Opens editor for profile display name, avatar, background image, and description`, - )}> - <Text type="button" style={pal.text}> - <Trans>Edit Profile</Trans> - </Text> - </TouchableOpacity> - ) : profile.viewer?.blocking ? ( - profile.viewer?.blockingByList ? null : ( - <TouchableOpacity - testID="unblockBtn" - onPress={onPressUnblockAccount} - style={[styles.btn, styles.mainBtn, pal.btn]} - accessibilityRole="button" - accessibilityLabel={_(msg`Unblock`)} - accessibilityHint=""> - <Text type="button" style={[pal.text, s.bold]}> - <Trans context="action">Unblock</Trans> - </Text> - </TouchableOpacity> - ) - ) : !profile.viewer?.blockedBy ? ( - <> - {hasSession && ( - <TouchableOpacity - testID="suggestedFollowsBtn" - onPress={() => setShowSuggestedFollows(!showSuggestedFollows)} - style={[ - styles.btn, - styles.mainBtn, - pal.btn, - { - paddingHorizontal: 10, - backgroundColor: showSuggestedFollows - ? pal.colors.text - : pal.colors.backgroundLight, - }, - ]} - accessibilityRole="button" - accessibilityLabel={_( - msg`Show follows similar to ${profile.handle}`, - )} - accessibilityHint={_( - msg`Shows a list of users similar to this user.`, - )}> - <FontAwesomeIcon - icon="user-plus" - style={[ - pal.text, - { - color: showSuggestedFollows - ? pal.textInverted.color - : pal.text.color, - }, - ]} - size={14} - /> - </TouchableOpacity> - )} - - {profile.viewer?.following ? ( - <TouchableOpacity - testID="unfollowBtn" - onPress={onPressUnfollow} - style={[styles.btn, styles.mainBtn, pal.btn]} - accessibilityRole="button" - accessibilityLabel={_(msg`Unfollow ${profile.handle}`)} - accessibilityHint={_( - msg`Hides posts from ${profile.handle} in your feed`, - )}> - <FontAwesomeIcon - icon="check" - style={[pal.text, s.mr5]} - size={14} - /> - <Text type="button" style={pal.text}> - <Trans>Following</Trans> - </Text> - </TouchableOpacity> - ) : ( - <TouchableOpacity - testID="followBtn" - onPress={onPressFollow} - style={[styles.btn, styles.mainBtn, palInverted.view]} - accessibilityRole="button" - accessibilityLabel={_(msg`Follow ${profile.handle}`)} - accessibilityHint={_( - msg`Shows posts from ${profile.handle} in your feed`, - )}> - <FontAwesomeIcon - icon="plus" - style={[palInverted.text, s.mr5]} - /> - <Text type="button" style={[palInverted.text, s.bold]}> - <Trans>Follow</Trans> - </Text> - </TouchableOpacity> - )} - </> - ) : null} - {dropdownItems?.length ? ( - <NativeDropdown - testID="profileHeaderDropdownBtn" - items={dropdownItems} - accessibilityLabel={_(msg`More options`)} - accessibilityHint=""> - <View style={[styles.btn, styles.secondaryBtn, pal.btn]}> - <FontAwesomeIcon icon="ellipsis" size={20} style={[pal.text]} /> - </View> - </NativeDropdown> - ) : undefined} - </View> - <View pointerEvents="none"> - <Text - testID="profileHeaderDisplayName" - type="title-2xl" - style={[pal.text, styles.title]}> - {sanitizeDisplayName( - profile.displayName || sanitizeHandle(profile.handle), - moderation.profile, - )} - </Text> - </View> - <View style={styles.handleLine} pointerEvents="none"> - {profile.viewer?.followedBy && !blockHide ? ( - <View style={[styles.pill, pal.btn, s.mr5]}> - <Text type="xs" style={[pal.text]}> - <Trans>Follows you</Trans> - </Text> - </View> - ) : undefined} - <ThemedText - type={invalidHandle ? 'xs' : 'md'} - fg={invalidHandle ? 'error' : 'light'} - border={invalidHandle ? 'error' : undefined} - style={[ - invalidHandle ? styles.invalidHandle : undefined, - styles.handle, - ]}> - {invalidHandle ? _(msg`âš Invalid Handle`) : `@${profile.handle}`} - </ThemedText> - </View> - {!isPlaceholderProfile && !blockHide && ( - <> - <View style={styles.metricsLine} pointerEvents="box-none"> - <Link - testID="profileHeaderFollowersButton" - style={[s.flexRow, s.mr10]} - href={makeProfileLink(profile, 'followers')} - onPressOut={() => - track(`ProfileHeader:FollowersButtonClicked`, { - handle: profile.handle, - }) - } - asAnchor - accessibilityLabel={`${followers} ${pluralizedFollowers}`} - accessibilityHint={_(msg`Opens followers list`)}> - <Text type="md" style={[s.bold, pal.text]}> - {followers}{' '} - </Text> - <Text type="md" style={[pal.textLight]}> - {pluralizedFollowers} - </Text> - </Link> - <Link - testID="profileHeaderFollowsButton" - style={[s.flexRow, s.mr10]} - href={makeProfileLink(profile, 'follows')} - onPressOut={() => - track(`ProfileHeader:FollowsButtonClicked`, { - handle: profile.handle, - }) - } - asAnchor - accessibilityLabel={_(msg`${following} following`)} - accessibilityHint={_(msg`Opens following list`)}> - <Trans> - <Text type="md" style={[s.bold, pal.text]}> - {following}{' '} - </Text> - <Text type="md" style={[pal.textLight]}> - following - </Text> - </Trans> - </Link> - <Text type="md" style={[s.bold, pal.text]}> - {formatCount(profile.postsCount || 0)}{' '} - <Text type="md" style={[pal.textLight]}> - {pluralize(profile.postsCount || 0, 'post')} - </Text> - </Text> - </View> - {descriptionRT && !moderation.profile.blur ? ( - <View pointerEvents="auto" style={[styles.description]}> - <RichText - testID="profileHeaderDescription" - style={[a.text_md]} - numberOfLines={15} - value={descriptionRT} - /> - </View> - ) : undefined} - </> - )} - <ProfileHeaderAlerts moderation={moderation} /> - {isMe && ( - <LabelInfo details={{did: profile.did}} labels={profile.labels} /> - )} - </View> - - {showSuggestedFollows && ( - <ProfileHeaderSuggestedFollows - actorDid={profile.did} - requestDismiss={() => { - if (showSuggestedFollows) { - setShowSuggestedFollows(false) - } else { - track('ProfileHeader:SuggestedFollowsOpened') - setShowSuggestedFollows(true) - } - }} - /> - )} - - {!isDesktop && !hideBackButton && ( - <TouchableWithoutFeedback - testID="profileHeaderBackBtn" - onPress={onPressBack} - hitSlop={BACK_HITSLOP} - accessibilityRole="button" - accessibilityLabel={_(msg`Back`)} - accessibilityHint=""> - <View style={styles.backBtnWrapper}> - <BlurView style={styles.backBtn} blurType="dark"> - <FontAwesomeIcon size={18} icon="angle-left" style={s.white} /> - </BlurView> - </View> - </TouchableWithoutFeedback> - )} - <TouchableWithoutFeedback - testID="profileHeaderAviButton" - onPress={onPressAvi} - accessibilityRole="image" - accessibilityLabel={_(msg`View ${profile.handle}'s avatar`)} - accessibilityHint=""> - <View - style={[pal.view, {borderColor: pal.colors.background}, styles.avi]}> - <UserAvatar - size={80} - avatar={profile.avatar} - moderation={moderation.avatar} - /> - </View> - </TouchableWithoutFeedback> - </View> - ) -} -ProfileHeader = memo(ProfileHeader) -export {ProfileHeader} - -const styles = StyleSheet.create({ - banner: { - width: '100%', - height: 120, - }, - backBtnWrapper: { - position: 'absolute', - top: 10, - left: 10, - width: 30, - height: 30, - overflow: 'hidden', - borderRadius: 15, - // @ts-ignore web only - cursor: 'pointer', - }, - backBtn: { - width: 30, - height: 30, - borderRadius: 15, - alignItems: 'center', - justifyContent: 'center', - }, - avi: { - position: 'absolute', - top: 110, - left: 10, - width: 84, - height: 84, - borderRadius: 42, - borderWidth: 2, - }, - content: { - paddingTop: 8, - paddingHorizontal: 14, - paddingBottom: 4, - }, - - buttonsLine: { - flexDirection: 'row', - marginLeft: 'auto', - marginBottom: 12, - }, - primaryBtn: { - backgroundColor: colors.blue3, - paddingHorizontal: 24, - paddingVertical: 6, - }, - mainBtn: { - paddingHorizontal: 24, - }, - secondaryBtn: { - paddingHorizontal: 14, - }, - btn: { - flexDirection: 'row', - alignItems: 'center', - justifyContent: 'center', - paddingVertical: 7, - borderRadius: 50, - marginLeft: 6, - }, - title: {lineHeight: 38}, - - // Word wrapping appears fine on - // mobile but overflows on desktop - handle: isNative - ? {} - : { - // @ts-ignore web only -prf - wordBreak: 'break-all', - }, - invalidHandle: { - borderWidth: 1, - borderRadius: 4, - paddingHorizontal: 4, - }, - - handleLine: { - flexDirection: 'row', - marginBottom: 8, - }, - - metricsLine: { - flexDirection: 'row', - marginBottom: 8, - }, - - description: { - marginBottom: 8, - }, - - detailLine: { - flexDirection: 'row', - alignItems: 'center', - marginBottom: 5, - }, - - pill: { - borderRadius: 4, - paddingHorizontal: 6, - paddingVertical: 2, - }, - - br40: {borderRadius: 40}, - br50: {borderRadius: 50}, -}) diff --git a/src/view/com/profile/ProfileHeaderSuggestedFollows.tsx b/src/view/com/profile/ProfileHeaderSuggestedFollows.tsx index 6edc61fcf..3602cdb9a 100644 --- a/src/view/com/profile/ProfileHeaderSuggestedFollows.tsx +++ b/src/view/com/profile/ProfileHeaderSuggestedFollows.tsx @@ -21,7 +21,8 @@ import {useModerationOpts} from '#/state/queries/preferences' import {useSuggestedFollowsByActorQuery} from '#/state/queries/suggested-follows' import {useProfileShadow} from '#/state/cache/profile-shadow' import {useProfileFollowMutationQueue} from '#/state/queries/profile' -import {Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {Trans, msg} from '@lingui/macro' const OUTER_PADDING = 10 const INNER_PADDING = 14 @@ -98,9 +99,11 @@ export function ProfileHeaderSuggestedFollows({ <SuggestedFollowSkeleton /> </> ) : data ? ( - data.suggestions.map(profile => ( - <SuggestedFollow key={profile.did} profile={profile} /> - )) + data.suggestions + .filter(s => (s.associated?.labeler ? false : true)) + .map(profile => ( + <SuggestedFollow key={profile.did} profile={profile} /> + )) ) : ( <View /> )} @@ -168,9 +171,13 @@ function SuggestedFollow({ }) { const {track} = useAnalytics() const pal = usePalette('default') + const {_} = useLingui() const moderationOpts = useModerationOpts() const profile = useProfileShadow(profileUnshadowed) - const [queueFollow, queueUnfollow] = useProfileFollowMutationQueue(profile) + const [queueFollow, queueUnfollow] = useProfileFollowMutationQueue( + profile, + 'ProfileHeaderSuggestedFollows', + ) const onPressFollow = React.useCallback(async () => { try { @@ -178,20 +185,20 @@ function SuggestedFollow({ await queueFollow() } catch (e: any) { if (e?.name !== 'AbortError') { - Toast.show('An issue occurred, please try again.') + Toast.show(_(msg`An issue occurred, please try again.`)) } } - }, [queueFollow, track]) + }, [queueFollow, track, _]) const onPressUnfollow = React.useCallback(async () => { try { await queueUnfollow() } catch (e: any) { if (e?.name !== 'AbortError') { - Toast.show('An issue occurred, please try again.') + Toast.show(_(msg`An issue occurred, please try again.`)) } } - }, [queueUnfollow]) + }, [queueUnfollow, _]) if (!moderationOpts) { return null @@ -214,7 +221,7 @@ function SuggestedFollow({ <UserAvatar size={60} avatar={profile.avatar} - moderation={moderation.avatar} + moderation={moderation.ui('avatar')} /> <View style={{width: '100%', paddingVertical: 12}}> @@ -224,7 +231,7 @@ function SuggestedFollow({ numberOfLines={1}> {sanitizeDisplayName( profile.displayName || sanitizeHandle(profile.handle), - moderation.profile, + moderation.ui('displayName'), )} </Text> <Text @@ -236,7 +243,7 @@ function SuggestedFollow({ </View> <Button - label={following ? 'Unfollow' : 'Follow'} + label={following ? _(msg`Unfollow`) : _(msg`Follow`)} type="inverted" labelStyle={{textAlign: 'center'}} onPress={following ? onPressUnfollow : onPressFollow} diff --git a/src/view/com/profile/ProfileMenu.tsx b/src/view/com/profile/ProfileMenu.tsx new file mode 100644 index 000000000..cb0b1d97c --- /dev/null +++ b/src/view/com/profile/ProfileMenu.tsx @@ -0,0 +1,380 @@ +import React, {memo} from 'react' +import {TouchableOpacity} from 'react-native' +import {AppBskyActorDefs} from '@atproto/api' +import {msg, Trans} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import {useQueryClient} from '@tanstack/react-query' +import * as Toast from 'view/com/util/Toast' +import {EventStopper} from 'view/com/util/EventStopper' +import {useSession} from 'state/session' +import * as Menu from '#/components/Menu' +import {useTheme} from '#/alf' +import {usePalette} from 'lib/hooks/usePalette' +import {HITSLOP_10} from 'lib/constants' +import {shareUrl} from 'lib/sharing' +import {toShareUrl} from 'lib/strings/url-helpers' +import {makeProfileLink} from 'lib/routes/links' +import {useAnalytics} from 'lib/analytics/analytics' +import {useModalControls} from 'state/modals' +import {ReportDialog, useReportDialogControl} from '#/components/ReportDialog' +import { + RQKEY as profileQueryKey, + useProfileBlockMutationQueue, + useProfileFollowMutationQueue, + useProfileMuteMutationQueue, +} from 'state/queries/profile' +import {ArrowOutOfBox_Stroke2_Corner0_Rounded as Share} from '#/components/icons/ArrowOutOfBox' +import {ListSparkle_Stroke2_Corner0_Rounded as List} from '#/components/icons/ListSparkle' +import {Mute_Stroke2_Corner0_Rounded as Mute} from '#/components/icons/Mute' +import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as Unmute} from '#/components/icons/Speaker' +import {Flag_Stroke2_Corner0_Rounded as Flag} from '#/components/icons/Flag' +import {PersonCheck_Stroke2_Corner0_Rounded as PersonCheck} from '#/components/icons/PersonCheck' +import {PersonX_Stroke2_Corner0_Rounded as PersonX} from '#/components/icons/PersonX' +import {PeopleRemove2_Stroke2_Corner0_Rounded as UserMinus} from '#/components/icons/PeopleRemove2' +import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus' +import {logger} from '#/logger' +import {Shadow} from 'state/cache/types' +import * as Prompt from '#/components/Prompt' + +let ProfileMenu = ({ + profile, +}: { + profile: Shadow<AppBskyActorDefs.ProfileViewDetailed> +}): React.ReactNode => { + const {_} = useLingui() + const {currentAccount, hasSession} = useSession() + const t = useTheme() + // TODO ALF this + const pal = usePalette('default') + const {track} = useAnalytics() + const {openModal} = useModalControls() + const reportDialogControl = useReportDialogControl() + const queryClient = useQueryClient() + const isSelf = currentAccount?.did === profile.did + const isFollowing = profile.viewer?.following + const isBlocked = profile.viewer?.blocking || profile.viewer?.blockedBy + const isFollowingBlockedAccount = isFollowing && isBlocked + const isLabelerAndNotBlocked = !!profile.associated?.labeler && !isBlocked + + const [queueMute, queueUnmute] = useProfileMuteMutationQueue(profile) + const [queueBlock, queueUnblock] = useProfileBlockMutationQueue(profile) + const [queueFollow, queueUnfollow] = useProfileFollowMutationQueue( + profile, + 'ProfileMenu', + ) + + const blockPromptControl = Prompt.usePromptControl() + const loggedOutWarningPromptControl = Prompt.usePromptControl() + + const showLoggedOutWarning = React.useMemo(() => { + return !!profile.labels?.find(label => label.val === '!no-unauthenticated') + }, [profile.labels]) + + const invalidateProfileQuery = React.useCallback(() => { + queryClient.invalidateQueries({ + queryKey: profileQueryKey(profile.did), + }) + }, [queryClient, profile.did]) + + const onPressShare = React.useCallback(() => { + track('ProfileHeader:ShareButtonClicked') + shareUrl(toShareUrl(makeProfileLink(profile))) + }, [track, profile]) + + const onPressAddRemoveLists = React.useCallback(() => { + track('ProfileHeader:AddToListsButtonClicked') + openModal({ + name: 'user-add-remove-lists', + subject: profile.did, + handle: profile.handle, + displayName: profile.displayName || profile.handle, + onAdd: invalidateProfileQuery, + onRemove: invalidateProfileQuery, + }) + }, [track, profile, openModal, invalidateProfileQuery]) + + const onPressMuteAccount = React.useCallback(async () => { + if (profile.viewer?.muted) { + track('ProfileHeader:UnmuteAccountButtonClicked') + try { + await queueUnmute() + Toast.show(_(msg`Account unmuted`)) + } catch (e: any) { + if (e?.name !== 'AbortError') { + logger.error('Failed to unmute account', {message: e}) + Toast.show(_(msg`There was an issue! ${e.toString()}`)) + } + } + } else { + track('ProfileHeader:MuteAccountButtonClicked') + try { + await queueMute() + Toast.show(_(msg`Account muted`)) + } catch (e: any) { + if (e?.name !== 'AbortError') { + logger.error('Failed to mute account', {message: e}) + Toast.show(_(msg`There was an issue! ${e.toString()}`)) + } + } + } + }, [profile.viewer?.muted, track, queueUnmute, _, queueMute]) + + const blockAccount = React.useCallback(async () => { + if (profile.viewer?.blocking) { + track('ProfileHeader:UnblockAccountButtonClicked') + try { + await queueUnblock() + Toast.show(_(msg`Account unblocked`)) + } catch (e: any) { + if (e?.name !== 'AbortError') { + logger.error('Failed to unblock account', {message: e}) + Toast.show(_(msg`There was an issue! ${e.toString()}`)) + } + } + } else { + track('ProfileHeader:BlockAccountButtonClicked') + try { + await queueBlock() + Toast.show(_(msg`Account blocked`)) + } catch (e: any) { + if (e?.name !== 'AbortError') { + logger.error('Failed to block account', {message: e}) + Toast.show(_(msg`There was an issue! ${e.toString()}`)) + } + } + } + }, [profile.viewer?.blocking, track, _, queueUnblock, queueBlock]) + + const onPressFollowAccount = React.useCallback(async () => { + track('ProfileHeader:FollowButtonClicked') + try { + await queueFollow() + Toast.show(_(msg`Account followed`)) + } catch (e: any) { + if (e?.name !== 'AbortError') { + logger.error('Failed to follow account', {message: e}) + Toast.show(_(msg`There was an issue! ${e.toString()}`)) + } + } + }, [_, queueFollow, track]) + + const onPressUnfollowAccount = React.useCallback(async () => { + track('ProfileHeader:UnfollowButtonClicked') + try { + await queueUnfollow() + Toast.show(_(msg`Account unfollowed`)) + } catch (e: any) { + if (e?.name !== 'AbortError') { + logger.error('Failed to unfollow account', {message: e}) + Toast.show(_(msg`There was an issue! ${e.toString()}`)) + } + } + }, [_, queueUnfollow, track]) + + const onPressReportAccount = React.useCallback(() => { + track('ProfileHeader:ReportAccountButtonClicked') + reportDialogControl.open() + }, [track, reportDialogControl]) + + return ( + <EventStopper onKeyDown={false}> + <Menu.Root> + <Menu.Trigger label={_(`More options`)}> + {({props}) => { + return ( + <TouchableOpacity + {...props} + hitSlop={HITSLOP_10} + testID="profileHeaderDropdownBtn" + style={[ + { + flexDirection: 'row', + alignItems: 'center', + justifyContent: 'center', + paddingVertical: 10, + borderRadius: 50, + paddingHorizontal: 16, + }, + pal.btn, + ]}> + <FontAwesomeIcon + icon="ellipsis" + size={20} + style={t.atoms.text} + /> + </TouchableOpacity> + ) + }} + </Menu.Trigger> + + <Menu.Outer style={{minWidth: 170}}> + <Menu.Group> + <Menu.Item + testID="profileHeaderDropdownShareBtn" + label={_(msg`Share`)} + onPress={() => { + if (showLoggedOutWarning) { + loggedOutWarningPromptControl.open() + } else { + onPressShare() + } + }}> + <Menu.ItemText> + <Trans>Share</Trans> + </Menu.ItemText> + <Menu.ItemIcon icon={Share} /> + </Menu.Item> + </Menu.Group> + + {hasSession && ( + <> + <Menu.Divider /> + <Menu.Group> + {!isSelf && ( + <> + {(isLabelerAndNotBlocked || isFollowingBlockedAccount) && ( + <Menu.Item + testID="profileHeaderDropdownFollowBtn" + label={ + isFollowing + ? _(msg`Unfollow Account`) + : _(msg`Follow Account`) + } + onPress={ + isFollowing + ? onPressUnfollowAccount + : onPressFollowAccount + }> + <Menu.ItemText> + {isFollowing ? ( + <Trans>Unfollow Account</Trans> + ) : ( + <Trans>Follow Account</Trans> + )} + </Menu.ItemText> + <Menu.ItemIcon icon={isFollowing ? UserMinus : Plus} /> + </Menu.Item> + )} + </> + )} + <Menu.Item + testID="profileHeaderDropdownListAddRemoveBtn" + label={_(msg`Add to Lists`)} + onPress={onPressAddRemoveLists}> + <Menu.ItemText> + <Trans>Add to Lists</Trans> + </Menu.ItemText> + <Menu.ItemIcon icon={List} /> + </Menu.Item> + {!isSelf && ( + <> + {!profile.viewer?.blocking && + !profile.viewer?.mutedByList && ( + <Menu.Item + testID="profileHeaderDropdownMuteBtn" + label={ + profile.viewer?.muted + ? _(msg`Unmute Account`) + : _(msg`Mute Account`) + } + onPress={onPressMuteAccount}> + <Menu.ItemText> + {profile.viewer?.muted ? ( + <Trans>Unmute Account</Trans> + ) : ( + <Trans>Mute Account</Trans> + )} + </Menu.ItemText> + <Menu.ItemIcon + icon={profile.viewer?.muted ? Unmute : Mute} + /> + </Menu.Item> + )} + {!profile.viewer?.blockingByList && ( + <Menu.Item + testID="profileHeaderDropdownBlockBtn" + label={ + profile.viewer + ? _(msg`Unblock Account`) + : _(msg`Block Account`) + } + onPress={() => blockPromptControl.open()}> + <Menu.ItemText> + {profile.viewer?.blocking ? ( + <Trans>Unblock Account</Trans> + ) : ( + <Trans>Block Account</Trans> + )} + </Menu.ItemText> + <Menu.ItemIcon + icon={ + profile.viewer?.blocking ? PersonCheck : PersonX + } + /> + </Menu.Item> + )} + <Menu.Item + testID="profileHeaderDropdownReportBtn" + label={_(msg`Report Account`)} + onPress={onPressReportAccount}> + <Menu.ItemText> + <Trans>Report Account</Trans> + </Menu.ItemText> + <Menu.ItemIcon icon={Flag} /> + </Menu.Item> + </> + )} + </Menu.Group> + </> + )} + </Menu.Outer> + </Menu.Root> + + <ReportDialog + control={reportDialogControl} + params={{type: 'account', did: profile.did}} + /> + + <Prompt.Basic + control={blockPromptControl} + title={ + profile.viewer?.blocking + ? _(msg`Unblock Account?`) + : _(msg`Block Account?`) + } + description={ + profile.viewer?.blocking + ? _( + msg`The account will be able to interact with you after unblocking.`, + ) + : profile.associated?.labeler + ? _( + msg`Blocking will not prevent labels from being applied on your account, but it will stop this account from replying in your threads or interacting with you.`, + ) + : _( + msg`Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you.`, + ) + } + onConfirm={blockAccount} + confirmButtonCta={ + profile.viewer?.blocking ? _(msg`Unblock`) : _(msg`Block`) + } + confirmButtonColor={profile.viewer?.blocking ? undefined : 'negative'} + /> + + <Prompt.Basic + control={loggedOutWarningPromptControl} + title={_(msg`Note about sharing`)} + description={_( + msg`This profile is only visible to logged-in users. It won't be visible to people who aren't logged in.`, + )} + onConfirm={onPressShare} + confirmButtonCta={_(msg`Share anyway`)} + /> + </EventStopper> + ) +} + +ProfileMenu = memo(ProfileMenu) +export {ProfileMenu} diff --git a/src/view/com/util/BottomSheetCustomBackdrop.tsx b/src/view/com/util/BottomSheetCustomBackdrop.tsx index ed5a2f165..ab6570252 100644 --- a/src/view/com/util/BottomSheetCustomBackdrop.tsx +++ b/src/view/com/util/BottomSheetCustomBackdrop.tsx @@ -6,12 +6,15 @@ import Animated, { interpolate, useAnimatedStyle, } from 'react-native-reanimated' -import {t} from '@lingui/macro' +import {msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' export function createCustomBackdrop( onClose?: (() => void) | undefined, ): React.FC<BottomSheetBackdropProps> { const CustomBackdrop = ({animatedIndex, style}: BottomSheetBackdropProps) => { + const {_} = useLingui() + // animated variables const opacity = useAnimatedStyle(() => ({ opacity: interpolate( @@ -30,7 +33,7 @@ export function createCustomBackdrop( return ( <TouchableWithoutFeedback onPress={onClose} - accessibilityLabel={t`Close bottom drawer`} + accessibilityLabel={_(msg`Close bottom drawer`)} accessibilityHint="" onAccessibilityEscape={() => { if (onClose !== undefined) { diff --git a/src/view/com/util/ErrorBoundary.tsx b/src/view/com/util/ErrorBoundary.tsx index 5ec1d0014..22fdd606e 100644 --- a/src/view/com/util/ErrorBoundary.tsx +++ b/src/view/com/util/ErrorBoundary.tsx @@ -1,8 +1,9 @@ import React, {Component, ErrorInfo, ReactNode} from 'react' import {ErrorScreen} from './error/ErrorScreen' import {CenteredView} from './Views' -import {t} from '@lingui/macro' +import {msg} from '@lingui/macro' import {logger} from '#/logger' +import {useLingui} from '@lingui/react' interface Props { children?: ReactNode @@ -31,11 +32,7 @@ export class ErrorBoundary extends Component<Props, State> { if (this.state.hasError) { return ( <CenteredView style={{height: '100%', flex: 1}}> - <ErrorScreen - title={t`Oh no!`} - message={t`There was an unexpected issue in the application. Please let us know if this happened to you!`} - details={this.state.error.toString()} - /> + <TranslatedErrorScreen details={this.state.error.toString()} /> </CenteredView> ) } @@ -43,3 +40,17 @@ export class ErrorBoundary extends Component<Props, State> { return this.props.children } } + +function TranslatedErrorScreen({details}: {details?: string}) { + const {_} = useLingui() + + return ( + <ErrorScreen + title={_(msg`Oh no!`)} + message={_( + msg`There was an unexpected issue in the application. Please let us know if this happened to you!`, + )} + details={details} + /> + ) +} diff --git a/src/view/com/util/Link.tsx b/src/view/com/util/Link.tsx index e50fb7f09..b6c512b09 100644 --- a/src/view/com/util/Link.tsx +++ b/src/view/com/util/Link.tsx @@ -8,17 +8,11 @@ import { View, ViewStyle, Pressable, - TouchableWithoutFeedback, TouchableOpacity, } from 'react-native' -import { - useLinkProps, - useNavigation, - StackActions, -} from '@react-navigation/native' +import {useLinkProps, StackActions} from '@react-navigation/native' import {Text} from './text/Text' import {TypographyVariant} from 'lib/ThemeContext' -import {NavigationProp} from 'lib/routes/types' import {router} from '../../../routes' import { convertBskyAppUrlIfNeeded, @@ -28,10 +22,14 @@ import { import {isAndroid, isWeb} from 'platform/detection' import {sanitizeUrl} from '@braintree/sanitize-url' import {PressableWithHover} from './PressableWithHover' -import FixedTouchableHighlight from '../pager/FixedTouchableHighlight' import {useModalControls} from '#/state/modals' import {useOpenLink} from '#/state/preferences/in-app-browser' import {WebAuxClickWrapper} from 'view/com/util/WebAuxClickWrapper' +import { + DebouncedNavigationProp, + useNavigationDeduped, +} from 'lib/hooks/useNavigationDeduped' +import {useTheme} from '#/alf' type Event = | React.MouseEvent<HTMLAnchorElement, MouseEvent> @@ -49,6 +47,7 @@ interface Props extends ComponentProps<typeof TouchableOpacity> { anchorNoUnderline?: boolean navigationAction?: 'push' | 'replace' | 'navigate' onPointerEnter?: () => void + onBeforePress?: () => void } export const Link = memo(function Link({ @@ -62,15 +61,18 @@ export const Link = memo(function Link({ accessible, anchorNoUnderline, navigationAction, + onBeforePress, ...props }: Props) { + const t = useTheme() const {closeModal} = useModalControls() - const navigation = useNavigation<NavigationProp>() + const navigation = useNavigationDeduped() const anchorHref = asAnchor ? sanitizeUrl(href) : undefined const openLink = useOpenLink() const onPress = React.useCallback( (e?: Event) => { + onBeforePress?.() if (typeof href === 'string') { return onPressInner( closeModal, @@ -82,41 +84,27 @@ export const Link = memo(function Link({ ) } }, - [closeModal, navigation, navigationAction, href, openLink], + [closeModal, navigation, navigationAction, href, openLink, onBeforePress], ) if (noFeedback) { - if (isAndroid) { - // workaround for Android not working well with left/right swipe gestures and TouchableWithoutFeedback - // https://github.com/callstack/react-native-pager-view/issues/424 - return ( - <FixedTouchableHighlight - testID={testID} - onPress={onPress} - // @ts-ignore web only -prf - href={asAnchor ? sanitizeUrl(href) : undefined} - accessible={accessible} - accessibilityRole="link" - {...props}> - <View style={style}> - {children ? children : <Text>{title || 'link'}</Text>} - </View> - </FixedTouchableHighlight> - ) - } return ( <WebAuxClickWrapper> - <TouchableWithoutFeedback + <Pressable testID={testID} onPress={onPress} accessible={accessible} accessibilityRole="link" - {...props}> + {...props} + android_ripple={{ + color: t.atoms.bg_contrast_25.backgroundColor, + }} + unstable_pressDelay={isAndroid ? 90 : undefined}> {/* @ts-ignore web only -prf */} <View style={style} href={anchorHref}> {children ? children : <Text>{title || 'link'}</Text>} </View> - </TouchableWithoutFeedback> + </Pressable> </WebAuxClickWrapper> ) } @@ -176,7 +164,7 @@ export const TextLink = memo(function TextLink({ navigationAction?: 'push' | 'replace' | 'navigate' } & TextProps) { const {...props} = useLinkProps({to: sanitizeUrl(href)}) - const navigation = useNavigation<NavigationProp>() + const navigation = useNavigationDeduped() const {openModal, closeModal} = useModalControls() const openLink = useOpenLink() @@ -277,6 +265,7 @@ interface TextLinkOnWebOnlyProps extends TextProps { accessibilityHint?: string title?: string navigationAction?: 'push' | 'replace' | 'navigate' + disableMismatchWarning?: boolean onPointerEnter?: () => void } export const TextLinkOnWebOnly = memo(function DesktopWebTextLink({ @@ -288,6 +277,7 @@ export const TextLinkOnWebOnly = memo(function DesktopWebTextLink({ numberOfLines, lineHeight, navigationAction, + disableMismatchWarning, ...props }: TextLinkOnWebOnlyProps) { if (isWeb) { @@ -302,6 +292,7 @@ export const TextLinkOnWebOnly = memo(function DesktopWebTextLink({ lineHeight={lineHeight} title={props.title} navigationAction={navigationAction} + disableMismatchWarning={disableMismatchWarning} {...props} /> ) @@ -335,7 +326,7 @@ const EXEMPT_PATHS = ['/robots.txt', '/security.txt', '/.well-known/'] // -prf function onPressInner( closeModal = () => {}, - navigation: NavigationProp, + navigation: DebouncedNavigationProp, href: string, navigationAction: 'push' | 'replace' | 'navigate' = 'push', openLink: (href: string) => void, diff --git a/src/view/com/util/PostMeta.tsx b/src/view/com/util/PostMeta.tsx index 3795dcf13..529fc54e0 100644 --- a/src/view/com/util/PostMeta.tsx +++ b/src/view/com/util/PostMeta.tsx @@ -11,16 +11,12 @@ import {sanitizeHandle} from 'lib/strings/handles' import {isAndroid, isWeb} from 'platform/detection' import {TimeElapsed} from './TimeElapsed' import {makeProfileLink} from 'lib/routes/links' -import {ModerationUI} from '@atproto/api' +import {AppBskyActorDefs, ModerationDecision, ModerationUI} from '@atproto/api' import {usePrefetchProfileQuery} from '#/state/queries/profile' interface PostMetaOpts { - author: { - avatar?: string - did: string - handle: string - displayName?: string | undefined - } + author: AppBskyActorDefs.ProfileViewBasic + moderation: ModerationDecision | undefined authorHasWarning: boolean postHref: string timestamp: string @@ -46,6 +42,7 @@ let PostMeta = (opts: PostMetaOpts): React.ReactNode => { avatar={opts.author.avatar} size={opts.avatarSize || 16} moderation={opts.avatarModeration} + type={opts.author.associated?.labeler ? 'labeler' : 'user'} /> </View> )} @@ -55,9 +52,14 @@ let PostMeta = (opts: PostMetaOpts): React.ReactNode => { style={[pal.text, opts.displayNameStyle]} numberOfLines={1} lineHeight={1.2} + disableMismatchWarning text={ <> - {sanitizeDisplayName(displayName)} + {sanitizeDisplayName( + displayName, + opts.moderation?.ui('displayName'), + )} + <Text type="md" numberOfLines={1} diff --git a/src/view/com/util/UserAvatar.tsx b/src/view/com/util/UserAvatar.tsx index f673db1ee..8656c3f51 100644 --- a/src/view/com/util/UserAvatar.tsx +++ b/src/view/com/util/UserAvatar.tsx @@ -1,9 +1,13 @@ import React, {memo, useMemo} from 'react' -import {Image, StyleSheet, View} from 'react-native' +import {Image, StyleSheet, TouchableOpacity, View} from 'react-native' import Svg, {Circle, Rect, Path} from 'react-native-svg' +import {Image as RNImage} from 'react-native-image-crop-picker' +import {useLingui} from '@lingui/react' +import {msg, Trans} from '@lingui/macro' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' -import {HighPriorityImage} from 'view/com/util/images/Image' import {ModerationUI} from '@atproto/api' + +import {HighPriorityImage} from 'view/com/util/images/Image' import {openCamera, openCropper, openPicker} from '../../../lib/media/picker' import { usePhotoLibraryPermission, @@ -11,14 +15,18 @@ import { } from 'lib/hooks/usePermissions' import {colors} from 'lib/styles' import {usePalette} from 'lib/hooks/usePalette' -import {isWeb, isAndroid} from 'platform/detection' -import {Image as RNImage} from 'react-native-image-crop-picker' +import {isWeb, isAndroid, isNative} from 'platform/detection' import {UserPreviewLink} from './UserPreviewLink' -import {DropdownItem, NativeDropdown} from './forms/NativeDropdown' -import {useLingui} from '@lingui/react' -import {msg} from '@lingui/macro' +import * as Menu from '#/components/Menu' +import { + Camera_Stroke2_Corner0_Rounded as Camera, + Camera_Filled_Stroke2_Corner0_Rounded as CameraFilled, +} from '#/components/icons/Camera' +import {StreamingLive_Stroke2_Corner0_Rounded as Library} from '#/components/icons/StreamingLive' +import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash' +import {useTheme, tokens} from '#/alf' -export type UserAvatarType = 'user' | 'algo' | 'list' +export type UserAvatarType = 'user' | 'algo' | 'list' | 'labeler' interface BaseUserAvatarProps { type?: UserAvatarType @@ -93,6 +101,33 @@ let DefaultAvatar = ({ </Svg> ) } + if (type === 'labeler') { + return ( + <Svg + testID="userAvatarFallback" + width={size} + height={size} + viewBox="0 0 32 32" + fill="none" + stroke="none"> + <Rect + x="0" + y="0" + width="32" + height="32" + rx="3" + fill={tokens.color.temp_purple} + /> + <Path + d="M24 9.75L16 7L8 9.75V15.9123C8 20.8848 12 23 16 25.1579C20 23 24 20.8848 24 15.9123V9.75Z" + stroke="white" + strokeWidth="2" + strokeLinecap="square" + strokeLinejoin="round" + /> + </Svg> + ) + } return ( <Svg testID="userAvatarFallback" @@ -126,7 +161,7 @@ let UserAvatar = ({ const backgroundColor = pal.colors.backgroundLight const aviStyle = useMemo(() => { - if (type === 'algo' || type === 'list') { + if (type === 'algo' || type === 'list' || type === 'labeler') { return { width: size, height: size, @@ -196,6 +231,7 @@ let EditableUserAvatar = ({ avatar, onSelectNewAvatar, }: EditableUserAvatarProps): React.ReactNode => { + const t = useTheme() const pal = usePalette('default') const {_} = useLingui() const {requestCameraAccessIfNeeded} = useCameraPermission() @@ -216,118 +252,115 @@ let EditableUserAvatar = ({ } }, [type, size]) - const dropdownItems = useMemo( - () => - [ - !isWeb && { - testID: 'changeAvatarCameraBtn', - label: _(msg`Camera`), - icon: { - ios: { - name: 'camera', - }, - android: 'ic_menu_camera', - web: 'camera', - }, - onPress: async () => { - if (!(await requestCameraAccessIfNeeded())) { - return - } + const onOpenCamera = React.useCallback(async () => { + if (!(await requestCameraAccessIfNeeded())) { + return + } + + onSelectNewAvatar( + await openCamera({ + width: 1000, + height: 1000, + cropperCircleOverlay: true, + }), + ) + }, [onSelectNewAvatar, requestCameraAccessIfNeeded]) + + const onOpenLibrary = React.useCallback(async () => { + if (!(await requestPhotoAccessIfNeeded())) { + return + } - onSelectNewAvatar( - await openCamera({ - width: 1000, - height: 1000, - cropperCircleOverlay: true, - }), - ) - }, - }, - { - testID: 'changeAvatarLibraryBtn', - label: _(msg`Library`), - icon: { - ios: { - name: 'photo.on.rectangle.angled', - }, - android: 'ic_menu_gallery', - web: 'gallery', - }, - onPress: async () => { - if (!(await requestPhotoAccessIfNeeded())) { - return - } + const items = await openPicker({ + aspect: [1, 1], + }) + const item = items[0] + if (!item) { + return + } - const items = await openPicker({ - aspect: [1, 1], - }) - const item = items[0] - if (!item) { - return - } + const croppedImage = await openCropper({ + mediaType: 'photo', + cropperCircleOverlay: true, + height: item.height, + width: item.width, + path: item.path, + }) - const croppedImage = await openCropper({ - mediaType: 'photo', - cropperCircleOverlay: true, - height: item.height, - width: item.width, - path: item.path, - }) + onSelectNewAvatar(croppedImage) + }, [onSelectNewAvatar, requestPhotoAccessIfNeeded]) - onSelectNewAvatar(croppedImage) - }, - }, - !!avatar && { - label: 'separator', - }, - !!avatar && { - testID: 'changeAvatarRemoveBtn', - label: _(msg`Remove`), - icon: { - ios: { - name: 'trash', - }, - android: 'ic_delete', - web: ['far', 'trash-can'], - }, - onPress: async () => { - onSelectNewAvatar(null) - }, - }, - ].filter(Boolean) as DropdownItem[], - [ - avatar, - onSelectNewAvatar, - requestCameraAccessIfNeeded, - requestPhotoAccessIfNeeded, - _, - ], - ) + const onRemoveAvatar = React.useCallback(() => { + onSelectNewAvatar(null) + }, [onSelectNewAvatar]) return ( - <NativeDropdown - testID="changeAvatarBtn" - items={dropdownItems} - accessibilityLabel={_(msg`Image options`)} - accessibilityHint=""> - {avatar ? ( - <HighPriorityImage - testID="userAvatarImage" - style={aviStyle} - source={{uri: avatar}} - accessibilityRole="image" - /> - ) : ( - <DefaultAvatar type={type} size={size} /> - )} - <View style={[styles.editButtonContainer, pal.btn]}> - <FontAwesomeIcon - icon="camera" - size={12} - color={pal.text.color as string} - /> - </View> - </NativeDropdown> + <Menu.Root> + <Menu.Trigger label={_(msg`Edit avatar`)}> + {({props}) => ( + <TouchableOpacity {...props} activeOpacity={0.8}> + {avatar ? ( + <HighPriorityImage + testID="userAvatarImage" + style={aviStyle} + source={{uri: avatar}} + accessibilityRole="image" + /> + ) : ( + <DefaultAvatar type={type} size={size} /> + )} + <View style={[styles.editButtonContainer, pal.btn]}> + <CameraFilled height={14} width={14} style={t.atoms.text} /> + </View> + </TouchableOpacity> + )} + </Menu.Trigger> + <Menu.Outer showCancel> + <Menu.Group> + {isNative && ( + <Menu.Item + testID="changeAvatarCameraBtn" + label={_(msg`Upload from Camera`)} + onPress={onOpenCamera}> + <Menu.ItemText> + <Trans>Upload from Camera</Trans> + </Menu.ItemText> + <Menu.ItemIcon icon={Camera} /> + </Menu.Item> + )} + + <Menu.Item + testID="changeAvatarLibraryBtn" + label={_(msg`Upload from Library`)} + onPress={onOpenLibrary}> + <Menu.ItemText> + {isNative ? ( + <Trans>Upload from Library</Trans> + ) : ( + <Trans>Upload from Files</Trans> + )} + </Menu.ItemText> + <Menu.ItemIcon icon={Library} /> + </Menu.Item> + </Menu.Group> + {!!avatar && ( + <> + <Menu.Divider /> + <Menu.Group> + <Menu.Item + testID="changeAvatarRemoveBtn" + label={_(`Remove Avatar`)} + onPress={onRemoveAvatar}> + <Menu.ItemText> + <Trans>Remove Avatar</Trans> + </Menu.ItemText> + <Menu.ItemIcon icon={Trash} /> + </Menu.Item> + </Menu.Group> + </> + )} + </Menu.Outer> + </Menu.Root> ) } EditableUserAvatar = memo(EditableUserAvatar) diff --git a/src/view/com/util/UserBanner.tsx b/src/view/com/util/UserBanner.tsx index cb47b6659..4fb3726cd 100644 --- a/src/view/com/util/UserBanner.tsx +++ b/src/view/com/util/UserBanner.tsx @@ -1,145 +1,157 @@ -import React, {useMemo} from 'react' -import {StyleSheet, View} from 'react-native' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import React from 'react' +import {StyleSheet, TouchableOpacity, View} from 'react-native' import {ModerationUI} from '@atproto/api' import {Image} from 'expo-image' import {useLingui} from '@lingui/react' -import {msg} from '@lingui/macro' +import {msg, Trans} from '@lingui/macro' + import {colors} from 'lib/styles' import {useTheme} from 'lib/ThemeContext' +import {useTheme as useAlfTheme, tokens} from '#/alf' import {openCamera, openCropper, openPicker} from '../../../lib/media/picker' import { usePhotoLibraryPermission, useCameraPermission, } from 'lib/hooks/usePermissions' import {usePalette} from 'lib/hooks/usePalette' -import {isWeb, isAndroid} from 'platform/detection' +import {isAndroid, isNative} from 'platform/detection' import {Image as RNImage} from 'react-native-image-crop-picker' -import {NativeDropdown, DropdownItem} from './forms/NativeDropdown' +import {EventStopper} from 'view/com/util/EventStopper' +import * as Menu from '#/components/Menu' +import { + Camera_Filled_Stroke2_Corner0_Rounded as CameraFilled, + Camera_Stroke2_Corner0_Rounded as Camera, +} from '#/components/icons/Camera' +import {StreamingLive_Stroke2_Corner0_Rounded as Library} from '#/components/icons/StreamingLive' +import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash' export function UserBanner({ + type, banner, moderation, onSelectNewBanner, }: { + type?: 'labeler' | 'default' banner?: string | null moderation?: ModerationUI onSelectNewBanner?: (img: RNImage | null) => void }) { const pal = usePalette('default') const theme = useTheme() + const t = useAlfTheme() const {_} = useLingui() const {requestCameraAccessIfNeeded} = useCameraPermission() const {requestPhotoAccessIfNeeded} = usePhotoLibraryPermission() - const dropdownItems: DropdownItem[] = useMemo( - () => - [ - !isWeb && { - testID: 'changeBannerCameraBtn', - label: _(msg`Camera`), - icon: { - ios: { - name: 'camera', - }, - android: 'ic_menu_camera', - web: 'camera', - }, - onPress: async () => { - if (!(await requestCameraAccessIfNeeded())) { - return - } - onSelectNewBanner?.( - await openCamera({ - width: 3000, - height: 1000, - }), - ) - }, - }, - { - testID: 'changeBannerLibraryBtn', - label: _(msg`Library`), - icon: { - ios: { - name: 'photo.on.rectangle.angled', - }, - android: 'ic_menu_gallery', - web: 'gallery', - }, - onPress: async () => { - if (!(await requestPhotoAccessIfNeeded())) { - return - } - const items = await openPicker() - if (!items[0]) { - return - } + const onOpenCamera = React.useCallback(async () => { + if (!(await requestCameraAccessIfNeeded())) { + return + } + onSelectNewBanner?.( + await openCamera({ + width: 3000, + height: 1000, + }), + ) + }, [onSelectNewBanner, requestCameraAccessIfNeeded]) - onSelectNewBanner?.( - await openCropper({ - mediaType: 'photo', - path: items[0].path, - width: 3000, - height: 1000, - }), - ) - }, - }, - !!banner && { - testID: 'changeBannerRemoveBtn', - label: _(msg`Remove`), - icon: { - ios: { - name: 'trash', - }, - android: 'ic_delete', - web: ['far', 'trash-can'], - }, - onPress: () => { - onSelectNewBanner?.(null) - }, - }, - ].filter(Boolean) as DropdownItem[], - [ - banner, - onSelectNewBanner, - requestCameraAccessIfNeeded, - requestPhotoAccessIfNeeded, - _, - ], - ) + const onOpenLibrary = React.useCallback(async () => { + if (!(await requestPhotoAccessIfNeeded())) { + return + } + const items = await openPicker() + if (!items[0]) { + return + } + + onSelectNewBanner?.( + await openCropper({ + mediaType: 'photo', + path: items[0].path, + width: 3000, + height: 1000, + }), + ) + }, [onSelectNewBanner, requestPhotoAccessIfNeeded]) + + const onRemoveBanner = React.useCallback(() => { + onSelectNewBanner?.(null) + }, [onSelectNewBanner]) // setUserBanner is only passed as prop on the EditProfile component return onSelectNewBanner ? ( - <NativeDropdown - testID="changeBannerBtn" - items={dropdownItems} - accessibilityLabel={_(msg`Image options`)} - accessibilityHint=""> - {banner ? ( - <Image - testID="userBannerImage" - style={styles.bannerImage} - source={{uri: banner}} - accessible={true} - accessibilityIgnoresInvertColors - /> - ) : ( - <View - testID="userBannerFallback" - style={[styles.bannerImage, styles.defaultBanner]} - /> - )} - <View style={[styles.editButtonContainer, pal.btn]}> - <FontAwesomeIcon - icon="camera" - size={12} - style={{color: colors.white}} - color={pal.text.color as string} - /> - </View> - </NativeDropdown> + <EventStopper onKeyDown={false}> + <Menu.Root> + <Menu.Trigger label={_(msg`Edit avatar`)}> + {({props}) => ( + <TouchableOpacity {...props} activeOpacity={0.8}> + {banner ? ( + <Image + testID="userBannerImage" + style={styles.bannerImage} + source={{uri: banner}} + accessible={true} + accessibilityIgnoresInvertColors + /> + ) : ( + <View + testID="userBannerFallback" + style={[styles.bannerImage, styles.defaultBanner]} + /> + )} + <View style={[styles.editButtonContainer, pal.btn]}> + <CameraFilled height={14} width={14} style={t.atoms.text} /> + </View> + </TouchableOpacity> + )} + </Menu.Trigger> + <Menu.Outer showCancel> + <Menu.Group> + {isNative && ( + <Menu.Item + testID="changeBannerCameraBtn" + label={_(msg`Upload from Camera`)} + onPress={onOpenCamera}> + <Menu.ItemText> + <Trans>Upload from Camera</Trans> + </Menu.ItemText> + <Menu.ItemIcon icon={Camera} /> + </Menu.Item> + )} + + <Menu.Item + testID="changeBannerLibraryBtn" + label={_(msg`Upload from Library`)} + onPress={onOpenLibrary}> + <Menu.ItemText> + {isNative ? ( + <Trans>Upload from Library</Trans> + ) : ( + <Trans>Upload from Files</Trans> + )} + </Menu.ItemText> + <Menu.ItemIcon icon={Library} /> + </Menu.Item> + </Menu.Group> + {!!banner && ( + <> + <Menu.Divider /> + <Menu.Group> + <Menu.Item + testID="changeBannerRemoveBtn" + label={_(`Remove Banner`)} + onPress={onRemoveBanner}> + <Menu.ItemText> + <Trans>Remove Banner</Trans> + </Menu.ItemText> + <Menu.ItemIcon icon={Trash} /> + </Menu.Item> + </Menu.Group> + </> + )} + </Menu.Outer> + </Menu.Root> + </EventStopper> ) : banner && !((moderation?.blur && isAndroid) /* android crashes with blur */) ? ( <Image @@ -157,7 +169,10 @@ export function UserBanner({ ) : ( <View testID="userBannerFallback" - style={[styles.bannerImage, styles.defaultBanner]} + style={[ + styles.bannerImage, + type === 'labeler' ? styles.labelerBanner : styles.defaultBanner, + ]} /> ) } @@ -181,4 +196,7 @@ const styles = StyleSheet.create({ defaultBanner: { backgroundColor: '#0070ff', }, + labelerBanner: { + backgroundColor: tokens.color.temp_purple, + }, }) diff --git a/src/view/com/util/forms/PostDropdownBtn.tsx b/src/view/com/util/forms/PostDropdownBtn.tsx index 6f2ae55b2..70fbb907f 100644 --- a/src/view/com/util/forms/PostDropdownBtn.tsx +++ b/src/view/com/util/forms/PostDropdownBtn.tsx @@ -1,11 +1,5 @@ import React, {memo} from 'react' -import { - StyleProp, - ViewStyle, - Pressable, - View, - PressableProps, -} from 'react-native' +import {StyleProp, ViewStyle, Pressable, PressableProps} from 'react-native' import Clipboard from '@react-native-clipboard/clipboard' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {useNavigation} from '@react-navigation/native' @@ -20,7 +14,8 @@ import {useTheme} from 'lib/ThemeContext' import {shareUrl} from 'lib/sharing' import * as Toast from '../Toast' import {EventStopper} from '../EventStopper' -import {useModalControls} from '#/state/modals' +import {useDialogControl} from '#/components/Dialog' +import * as Prompt from '#/components/Prompt' import {makeProfileLink} from '#/lib/routes/links' import {CommonNavigatorParams} from '#/lib/routes/types' import {getCurrentRoute} from 'lib/routes/helpers' @@ -37,8 +32,9 @@ import {useSession} from '#/state/session' import {isWeb} from '#/platform/detection' import {richTextToString} from '#/lib/strings/rich-text-helpers' import {useGlobalDialogsControlContext} from '#/components/dialogs/Context' +import {ReportDialog, useReportDialogControl} from '#/components/ReportDialog' -import {atoms as a, useTheme as useAlf, web} from '#/alf' +import {atoms as a, useTheme as useAlf} from '#/alf' import * as Menu from '#/components/Menu' import {Clipboard_Stroke2_Corner2_Rounded as ClipboardIcon} from '#/components/icons/Clipboard' import {Filter_Stroke2_Corner0_Rounded as Filter} from '#/components/icons/Filter' @@ -49,7 +45,6 @@ import {SpeakerVolumeFull_Stroke2_Corner0_Rounded as Unmute} from '#/components/ import {BubbleQuestion_Stroke2_Corner0_Rounded as Translate} from '#/components/icons/Bubble' import {Warning_Stroke2_Corner0_Rounded as Warning} from '#/components/icons/Warning' import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash' -import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo' let PostDropdownBtn = ({ testID, @@ -59,7 +54,6 @@ let PostDropdownBtn = ({ record, richText, style, - showAppealLabelItem, hitSlop, }: { testID: string @@ -69,7 +63,6 @@ let PostDropdownBtn = ({ record: AppBskyFeedPost.Record richText: RichTextAPI style?: StyleProp<ViewStyle> - showAppealLabelItem?: boolean hitSlop?: PressableProps['hitSlop'] }): React.ReactNode => { const {hasSession, currentAccount} = useSession() @@ -77,7 +70,6 @@ let PostDropdownBtn = ({ const alf = useAlf() const {_} = useLingui() const defaultCtrlColor = theme.palette.default.postCtrl - const {openModal} = useModalControls() const langPrefs = useLanguagePrefs() const mutedThreads = useMutedThreads() const toggleThreadMute = useToggleThreadMute() @@ -87,11 +79,16 @@ let PostDropdownBtn = ({ const openLink = useOpenLink() const navigation = useNavigation() const {mutedWordsDialogControl} = useGlobalDialogsControlContext() + const reportDialogControl = useReportDialogControl() + const deletePromptControl = useDialogControl() + const hidePromptControl = useDialogControl() + const loggedOutWarningPromptControl = useDialogControl() const rootUri = record.reply?.root?.uri || postUri const isThreadMuted = mutedThreads.includes(rootUri) const isPostHidden = hiddenPosts && hiddenPosts.includes(postUri) const isAuthor = postAuthor.did === currentAccount?.did + const href = React.useMemo(() => { const urip = new AtUri(postUri) return makeProfileLink(postAuthor, 'post', urip.rkey) @@ -169,34 +166,34 @@ let PostDropdownBtn = ({ hidePost({uri: postUri}) }, [postUri, hidePost]) + const shouldShowLoggedOutWarning = React.useMemo(() => { + return !!postAuthor.labels?.find( + label => label.val === '!no-unauthenticated', + ) + }, [postAuthor]) + + const onSharePost = React.useCallback(() => { + const url = toShareUrl(href) + shareUrl(url) + }, [href]) + return ( <EventStopper onKeyDown={false}> <Menu.Root> <Menu.Trigger label={_(msg`Open post options menu`)}> {({props, state}) => { - const styles = [ - style, - a.rounded_full, - (state.hovered || state.focused || state.pressed) && [ - web({outline: 0}), - alf.atoms.bg_contrast_25, - ], - ] - return isWeb ? ( - <View {...props} testID={testID} style={styles}> - <FontAwesomeIcon - icon="ellipsis" - size={20} - color={defaultCtrlColor} - style={{pointerEvents: 'none'}} - /> - </View> - ) : ( + return ( <Pressable {...props} hitSlop={hitSlop} testID={testID} - style={styles}> + style={[ + style, + a.rounded_full, + (state.hovered || state.pressed) && [ + alf.atoms.bg_contrast_50, + ], + ]}> <FontAwesomeIcon icon="ellipsis" size={20} @@ -230,8 +227,11 @@ let PostDropdownBtn = ({ testID="postDropdownShareBtn" label={isWeb ? _(msg`Copy link to post`) : _(msg`Share`)} onPress={() => { - const url = toShareUrl(href) - shareUrl(url) + if (shouldShowLoggedOutWarning) { + loggedOutWarningPromptControl.open() + } else { + onSharePost() + } }}> <Menu.ItemText> {isWeb ? _(msg`Copy link to post`) : _(msg`Share`)} @@ -274,16 +274,7 @@ let PostDropdownBtn = ({ <Menu.Item testID="postDropdownHideBtn" label={_(msg`Hide post`)} - onPress={() => { - openModal({ - name: 'confirm', - title: _(msg`Hide this post?`), - message: _( - msg`This will hide this post from your feeds.`, - ), - onPressConfirm: onHidePost, - }) - }}> + onPress={hidePromptControl.open}> <Menu.ItemText>{_(msg`Hide post`)}</Menu.ItemText> <Menu.ItemIcon icon={EyeSlash} position="right" /> </Menu.Item> @@ -299,13 +290,7 @@ let PostDropdownBtn = ({ <Menu.Item testID="postDropdownReportBtn" label={_(msg`Report post`)} - onPress={() => { - openModal({ - name: 'report', - uri: postUri, - cid: postCid, - }) - }}> + onPress={() => reportDialogControl.open()}> <Menu.ItemText>{_(msg`Report post`)}</Menu.ItemText> <Menu.ItemIcon icon={Warning} position="right" /> </Menu.Item> @@ -315,43 +300,52 @@ let PostDropdownBtn = ({ <Menu.Item testID="postDropdownDeleteBtn" label={_(msg`Delete post`)} - onPress={() => { - openModal({ - name: 'confirm', - title: _(msg`Delete this post?`), - message: _(msg`Are you sure? This cannot be undone.`), - onPressConfirm: onDeletePost, - }) - }}> + onPress={deletePromptControl.open}> <Menu.ItemText>{_(msg`Delete post`)}</Menu.ItemText> <Menu.ItemIcon icon={Trash} position="right" /> </Menu.Item> )} - - {showAppealLabelItem && ( - <> - <Menu.Divider /> - - <Menu.Item - testID="postDropdownAppealBtn" - label={_(msg`Appeal content warning`)} - onPress={() => { - openModal({ - name: 'appeal-label', - uri: postUri, - cid: postCid, - }) - }}> - <Menu.ItemText> - {_(msg`Appeal content warning`)} - </Menu.ItemText> - <Menu.ItemIcon icon={CircleInfo} position="right" /> - </Menu.Item> - </> - )} </Menu.Group> </Menu.Outer> </Menu.Root> + + <Prompt.Basic + control={deletePromptControl} + title={_(msg`Delete this post?`)} + description={_( + msg`If you remove this post, you won't be able to recover it.`, + )} + onConfirm={onDeletePost} + confirmButtonCta={_(msg`Delete`)} + confirmButtonColor="negative" + /> + + <Prompt.Basic + control={hidePromptControl} + title={_(msg`Hide this post?`)} + description={_(msg`This post will be hidden from feeds.`)} + onConfirm={onHidePost} + confirmButtonCta={_(msg`Hide`)} + /> + + <ReportDialog + control={reportDialogControl} + params={{ + type: 'post', + uri: postUri, + cid: postCid, + }} + /> + + <Prompt.Basic + control={loggedOutWarningPromptControl} + title={_(msg`Note about sharing`)} + description={_( + msg`This post is only visible to logged-in users. It won't be visible to people who aren't logged in.`, + )} + onConfirm={onSharePost} + confirmButtonCta={_(msg`Share anyway`)} + /> </EventStopper> ) } diff --git a/src/view/com/util/load-latest/LoadLatestBtn.tsx b/src/view/com/util/load-latest/LoadLatestBtn.tsx index 5fad11760..f02e4a2bd 100644 --- a/src/view/com/util/load-latest/LoadLatestBtn.tsx +++ b/src/view/com/util/load-latest/LoadLatestBtn.tsx @@ -1,12 +1,13 @@ import React from 'react' import {StyleSheet, TouchableOpacity, View} from 'react-native' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' +import Animated from 'react-native-reanimated' +import {useMediaQuery} from 'react-responsive' import {usePalette} from 'lib/hooks/usePalette' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' import {colors} from 'lib/styles' import {HITSLOP_20} from 'lib/constants' import {useMinimalShellMode} from 'lib/hooks/useMinimalShellMode' -import Animated from 'react-native-reanimated' const AnimatedTouchableOpacity = Animated.createAnimatedComponent(TouchableOpacity) import {isWeb} from 'platform/detection' @@ -26,6 +27,9 @@ export function LoadLatestBtn({ const {isDesktop, isTablet, isMobile, isTabletOrMobile} = useWebMediaQueries() const {fabMinimalShellTransform} = useMinimalShellMode() + // move button inline if it starts overlapping the left nav + const isTallViewport = useMediaQuery({minHeight: 700}) + // Adjust height of the fab if we have a session only on mobile web. If we don't have a session, we want to adjust // it on both tablet and mobile since we are showing the bottom bar (see createNativeStackNavigatorWithAuth) const showBottomBar = hasSession ? isMobile : isTabletOrMobile @@ -34,8 +38,11 @@ export function LoadLatestBtn({ <AnimatedTouchableOpacity style={[ styles.loadLatest, - isDesktop && styles.loadLatestDesktop, - isTablet && styles.loadLatestTablet, + isDesktop && + (isTallViewport + ? styles.loadLatestOutOfLine + : styles.loadLatestInline), + isTablet && styles.loadLatestInline, pal.borderDark, pal.view, showBottomBar && fabMinimalShellTransform, @@ -65,11 +72,11 @@ const styles = StyleSheet.create({ alignItems: 'center', justifyContent: 'center', }, - loadLatestTablet: { + loadLatestInline: { // @ts-ignore web only left: 'calc(50vw - 282px)', }, - loadLatestDesktop: { + loadLatestOutOfLine: { // @ts-ignore web only left: 'calc(50vw - 382px)', }, diff --git a/src/view/com/util/moderation/ContentHider.tsx b/src/view/com/util/moderation/ContentHider.tsx deleted file mode 100644 index cd2545290..000000000 --- a/src/view/com/util/moderation/ContentHider.tsx +++ /dev/null @@ -1,145 +0,0 @@ -import React from 'react' -import {Pressable, StyleProp, StyleSheet, View, ViewStyle} from 'react-native' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' -import {usePalette} from 'lib/hooks/usePalette' -import {ModerationUI, PostModeration} from '@atproto/api' -import {Text} from '../text/Text' -import {ShieldExclamation} from 'lib/icons' -import {describeModerationCause} from 'lib/moderation' -import {useLingui} from '@lingui/react' -import {msg, Trans} from '@lingui/macro' -import {useModalControls} from '#/state/modals' -import {isPostMediaBlurred} from 'lib/moderation' - -export function ContentHider({ - testID, - moderation, - moderationDecisions, - ignoreMute, - ignoreQuoteDecisions, - style, - childContainerStyle, - children, -}: React.PropsWithChildren<{ - testID?: string - moderation: ModerationUI - moderationDecisions?: PostModeration['decisions'] - ignoreMute?: boolean - ignoreQuoteDecisions?: boolean - style?: StyleProp<ViewStyle> - childContainerStyle?: StyleProp<ViewStyle> -}>) { - const pal = usePalette('default') - const {_} = useLingui() - const [override, setOverride] = React.useState(false) - const {openModal} = useModalControls() - - if ( - !moderation.blur || - (ignoreMute && moderation.cause?.type === 'muted') || - shouldIgnoreQuote(moderationDecisions, ignoreQuoteDecisions) - ) { - return ( - <View testID={testID} style={[styles.outer, style]}> - {children} - </View> - ) - } - - const isMute = ['muted', 'muted-word'].includes(moderation.cause?.type || '') - const desc = describeModerationCause(moderation.cause, 'content') - return ( - <View testID={testID} style={[styles.outer, style]}> - <Pressable - onPress={() => { - if (!moderation.noOverride) { - setOverride(v => !v) - } else { - openModal({ - name: 'moderation-details', - context: 'content', - moderation, - }) - } - }} - accessibilityRole="button" - accessibilityHint={ - override ? _(msg`Hide the content`) : _(msg`Show the content`) - } - accessibilityLabel="" - style={[ - styles.cover, - moderation.noOverride - ? {borderWidth: 1, borderColor: pal.colors.borderDark} - : pal.viewLight, - ]}> - <Pressable - onPress={() => { - openModal({ - name: 'moderation-details', - context: 'content', - moderation, - }) - }} - accessibilityRole="button" - accessibilityLabel={_(msg`Learn more about this warning`)} - accessibilityHint=""> - {isMute ? ( - <FontAwesomeIcon - icon={['far', 'eye-slash']} - size={18} - color={pal.colors.textLight} - /> - ) : ( - <ShieldExclamation size={18} style={pal.textLight} /> - )} - </Pressable> - <Text type="md" style={[pal.text, {flex: 1}]} numberOfLines={2}> - {desc.name} - </Text> - <View style={styles.showBtn}> - <Text type="lg" style={pal.link}> - {moderation.noOverride ? ( - <Trans>Learn more</Trans> - ) : override ? ( - <Trans>Hide</Trans> - ) : ( - <Trans>Show</Trans> - )} - </Text> - </View> - </Pressable> - {override && <View style={childContainerStyle}>{children}</View>} - </View> - ) -} - -function shouldIgnoreQuote( - decisions: PostModeration['decisions'] | undefined, - ignore: boolean | undefined, -): boolean { - if (!decisions || !ignore) { - return false - } - return !isPostMediaBlurred(decisions) -} - -const styles = StyleSheet.create({ - outer: { - overflow: 'hidden', - }, - cover: { - flexDirection: 'row', - alignItems: 'center', - gap: 6, - borderRadius: 8, - marginTop: 4, - paddingVertical: 14, - paddingLeft: 14, - paddingRight: 18, - }, - showBtn: { - marginLeft: 'auto', - alignSelf: 'center', - }, -}) diff --git a/src/view/com/util/moderation/LabelInfo.tsx b/src/view/com/util/moderation/LabelInfo.tsx deleted file mode 100644 index 970338752..000000000 --- a/src/view/com/util/moderation/LabelInfo.tsx +++ /dev/null @@ -1,61 +0,0 @@ -import React from 'react' -import {Pressable, StyleProp, View, ViewStyle} from 'react-native' -import {ComAtprotoLabelDefs} from '@atproto/api' -import {Text} from '../text/Text' -import {usePalette} from 'lib/hooks/usePalette' -import {msg, Trans} from '@lingui/macro' -import {useLingui} from '@lingui/react' -import {useModalControls} from '#/state/modals' - -export function LabelInfo({ - details, - labels, - style, -}: { - details: {did: string} | {uri: string; cid: string} - labels: ComAtprotoLabelDefs.Label[] | undefined - style?: StyleProp<ViewStyle> -}) { - const pal = usePalette('default') - const {_} = useLingui() - const {openModal} = useModalControls() - - if (!labels) { - return null - } - labels = labels.filter(l => !l.val.startsWith('!')) - if (!labels.length) { - return null - } - - return ( - <View - style={[ - pal.viewLight, - { - flexDirection: 'row', - flexWrap: 'wrap', - paddingHorizontal: 12, - paddingVertical: 10, - borderRadius: 8, - }, - style, - ]}> - <Text type="sm" style={pal.text}> - <Trans> - A content warning has been applied to this{' '} - {'did' in details ? 'account' : 'post'}. - </Trans>{' '} - </Text> - <Pressable - accessibilityRole="button" - accessibilityLabel={_(msg`Appeal this decision`)} - accessibilityHint="" - onPress={() => openModal({name: 'appeal-label', ...details})}> - <Text type="sm" style={pal.link}> - <Trans>Appeal this decision.</Trans> - </Text> - </Pressable> - </View> - ) -} diff --git a/src/view/com/util/moderation/PostAlerts.tsx b/src/view/com/util/moderation/PostAlerts.tsx deleted file mode 100644 index bc5bf9b32..000000000 --- a/src/view/com/util/moderation/PostAlerts.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import React from 'react' -import {Pressable, StyleProp, StyleSheet, ViewStyle} from 'react-native' -import {ModerationUI} from '@atproto/api' -import {Text} from '../text/Text' -import {usePalette} from 'lib/hooks/usePalette' -import {ShieldExclamation} from 'lib/icons' -import {describeModerationCause} from 'lib/moderation' -import {Trans, msg} from '@lingui/macro' -import {useLingui} from '@lingui/react' -import {useModalControls} from '#/state/modals' - -export function PostAlerts({ - moderation, - style, -}: { - moderation: ModerationUI - includeMute?: boolean - style?: StyleProp<ViewStyle> -}) { - const pal = usePalette('default') - const {_} = useLingui() - const {openModal} = useModalControls() - - const shouldAlert = !!moderation.cause && moderation.alert - if (!shouldAlert) { - return null - } - - const desc = describeModerationCause(moderation.cause, 'content') - return ( - <Pressable - onPress={() => { - openModal({ - name: 'moderation-details', - context: 'content', - moderation, - }) - }} - accessibilityRole="button" - accessibilityLabel={_(msg`Learn more about this warning`)} - accessibilityHint="" - style={[styles.container, pal.viewLight, style]}> - <ShieldExclamation style={pal.text} size={16} /> - <Text type="lg" style={[pal.text]}> - {desc.name}{' '} - <Text type="lg" style={[pal.link, styles.learnMoreBtn]}> - <Trans>Learn More</Trans> - </Text> - </Text> - </Pressable> - ) -} - -const styles = StyleSheet.create({ - container: { - flexDirection: 'row', - alignItems: 'center', - gap: 4, - paddingVertical: 8, - paddingLeft: 14, - paddingHorizontal: 16, - borderRadius: 8, - }, - learnMoreBtn: { - marginLeft: 'auto', - }, -}) diff --git a/src/view/com/util/moderation/ProfileHeaderAlerts.tsx b/src/view/com/util/moderation/ProfileHeaderAlerts.tsx deleted file mode 100644 index 0f07b679b..000000000 --- a/src/view/com/util/moderation/ProfileHeaderAlerts.tsx +++ /dev/null @@ -1,89 +0,0 @@ -import React from 'react' -import {Pressable, StyleProp, StyleSheet, View, ViewStyle} from 'react-native' -import {ProfileModeration} from '@atproto/api' -import {Text} from '../text/Text' -import {usePalette} from 'lib/hooks/usePalette' -import {ShieldExclamation} from 'lib/icons' -import { - describeModerationCause, - getProfileModerationCauses, -} from 'lib/moderation' -import {msg, Trans} from '@lingui/macro' -import {useLingui} from '@lingui/react' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' -import {useModalControls} from '#/state/modals' - -export function ProfileHeaderAlerts({ - moderation, - style, -}: { - moderation: ProfileModeration - style?: StyleProp<ViewStyle> -}) { - const pal = usePalette('default') - const {_} = useLingui() - const {openModal} = useModalControls() - - const causes = getProfileModerationCauses(moderation) - if (!causes.length) { - return null - } - - return ( - <View style={styles.grid}> - {causes.map(cause => { - const isMute = cause.type === 'muted' - const desc = describeModerationCause(cause, 'account') - return ( - <Pressable - testID="profileHeaderAlert" - key={desc.name} - onPress={() => { - openModal({ - name: 'moderation-details', - context: 'content', - moderation: {cause}, - }) - }} - accessibilityRole="button" - accessibilityLabel={_(msg`Learn more about this warning`)} - accessibilityHint="" - style={[styles.container, pal.viewLight, style]}> - {isMute ? ( - <FontAwesomeIcon - icon={['far', 'eye-slash']} - size={14} - color={pal.colors.textLight} - /> - ) : ( - <ShieldExclamation style={pal.text} size={18} /> - )} - <Text type="sm" style={[{flex: 1}, pal.text]}> - {desc.name} - </Text> - <Text type="sm" style={[pal.link, styles.learnMoreBtn]}> - <Trans>Learn More</Trans> - </Text> - </Pressable> - ) - })} - </View> - ) -} - -const styles = StyleSheet.create({ - grid: { - gap: 4, - }, - container: { - flexDirection: 'row', - alignItems: 'center', - gap: 8, - paddingVertical: 12, - paddingHorizontal: 16, - borderRadius: 8, - }, - learnMoreBtn: { - marginLeft: 'auto', - }, -}) diff --git a/src/view/com/util/moderation/ScreenHider.tsx b/src/view/com/util/moderation/ScreenHider.tsx deleted file mode 100644 index 86f0cbf7b..000000000 --- a/src/view/com/util/moderation/ScreenHider.tsx +++ /dev/null @@ -1,180 +0,0 @@ -import React from 'react' -import { - TouchableWithoutFeedback, - StyleProp, - StyleSheet, - View, - ViewStyle, -} from 'react-native' -import { - FontAwesomeIcon, - FontAwesomeIconStyle, -} from '@fortawesome/react-native-fontawesome' -import {useNavigation} from '@react-navigation/native' -import {ModerationUI} from '@atproto/api' -import {usePalette} from 'lib/hooks/usePalette' -import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' -import {NavigationProp} from 'lib/routes/types' -import {Text} from '../text/Text' -import {Button} from '../forms/Button' -import {describeModerationCause} from 'lib/moderation' -import {Trans, msg} from '@lingui/macro' -import {useLingui} from '@lingui/react' -import {useModalControls} from '#/state/modals' -import {s} from '#/lib/styles' -import {CenteredView} from '../Views' - -export function ScreenHider({ - testID, - screenDescription, - moderation, - style, - containerStyle, - children, -}: React.PropsWithChildren<{ - testID?: string - screenDescription: string - moderation: ModerationUI - style?: StyleProp<ViewStyle> - containerStyle?: StyleProp<ViewStyle> -}>) { - const pal = usePalette('default') - const palInverted = usePalette('inverted') - const {_} = useLingui() - const [override, setOverride] = React.useState(false) - const navigation = useNavigation<NavigationProp>() - const {isMobile} = useWebMediaQueries() - const {openModal} = useModalControls() - - if (!moderation.blur || override) { - return ( - <View testID={testID} style={style}> - {children} - </View> - ) - } - - const isNoPwi = - moderation.cause?.type === 'label' && - moderation.cause?.labelDef.id === '!no-unauthenticated' - const desc = describeModerationCause(moderation.cause, 'account') - return ( - <CenteredView - style={[styles.container, pal.view, containerStyle]} - sideBorders> - <View style={styles.iconContainer}> - <View style={[styles.icon, palInverted.view]}> - <FontAwesomeIcon - icon={isNoPwi ? ['far', 'eye-slash'] : 'exclamation'} - style={pal.textInverted as FontAwesomeIconStyle} - size={24} - /> - </View> - </View> - <Text type="title-2xl" style={[styles.title, pal.text]}> - {isNoPwi ? ( - <Trans>Sign-in Required</Trans> - ) : ( - <Trans>Content Warning</Trans> - )} - </Text> - <Text type="2xl" style={[styles.description, pal.textLight]}> - {isNoPwi ? ( - <Trans> - This account has requested that users sign in to view their profile. - </Trans> - ) : ( - <> - <Trans>This {screenDescription} has been flagged:</Trans> - <Text type="2xl-medium" style={[pal.text, s.ml5]}> - {desc.name}. - </Text> - <TouchableWithoutFeedback - onPress={() => { - openModal({ - name: 'moderation-details', - context: 'account', - moderation, - }) - }} - accessibilityRole="button" - accessibilityLabel={_(msg`Learn more about this warning`)} - accessibilityHint=""> - <Text type="2xl" style={pal.link}> - <Trans>Learn More</Trans> - </Text> - </TouchableWithoutFeedback> - </> - )}{' '} - </Text> - {isMobile && <View style={styles.spacer} />} - <View style={styles.btnContainer}> - <Button - type="inverted" - onPress={() => { - if (navigation.canGoBack()) { - navigation.goBack() - } else { - navigation.navigate('Home') - } - }} - style={styles.btn}> - <Text type="button-lg" style={pal.textInverted}> - <Trans>Go back</Trans> - </Text> - </Button> - {!moderation.noOverride && ( - <Button - type="default" - onPress={() => setOverride(v => !v)} - style={styles.btn}> - <Text type="button-lg" style={pal.text}> - <Trans>Show anyway</Trans> - </Text> - </Button> - )} - </View> - </CenteredView> - ) -} - -const styles = StyleSheet.create({ - spacer: { - flex: 1, - }, - container: { - flex: 1, - paddingTop: 100, - paddingBottom: 150, - }, - iconContainer: { - alignItems: 'center', - marginBottom: 10, - }, - icon: { - borderRadius: 25, - width: 50, - height: 50, - alignItems: 'center', - justifyContent: 'center', - }, - title: { - textAlign: 'center', - marginBottom: 10, - }, - description: { - marginBottom: 10, - paddingHorizontal: 20, - textAlign: 'center', - }, - btnContainer: { - flexDirection: 'row', - justifyContent: 'center', - marginVertical: 10, - gap: 10, - }, - btn: { - paddingHorizontal: 20, - paddingVertical: 14, - }, -}) diff --git a/src/view/com/util/post-ctrls/PostCtrls.tsx b/src/view/com/util/post-ctrls/PostCtrls.tsx index 1e26eecce..3fa347a6d 100644 --- a/src/view/com/util/post-ctrls/PostCtrls.tsx +++ b/src/view/com/util/post-ctrls/PostCtrls.tsx @@ -41,24 +41,27 @@ let PostCtrls = ({ post, record, richText, - showAppealLabelItem, style, onPressReply, + logContext, }: { big?: boolean post: Shadow<AppBskyFeedDefs.PostView> record: AppBskyFeedPost.Record richText: RichTextAPI - showAppealLabelItem?: boolean style?: StyleProp<ViewStyle> onPressReply: () => void + logContext: 'FeedItem' | 'PostThreadItem' | 'Post' }): React.ReactNode => { const theme = useTheme() const {_} = useLingui() const {openComposer} = useComposerControls() const {closeModal} = useModalControls() - const [queueLike, queueUnlike] = usePostLikeMutationQueue(post) - const [queueRepost, queueUnrepost] = usePostRepostMutationQueue(post) + const [queueLike, queueUnlike] = usePostLikeMutationQueue(post, logContext) + const [queueRepost, queueUnrepost] = usePostRepostMutationQueue( + post, + logContext, + ) const requireAuth = useRequireAuth() const defaultCtrlColor = React.useMemo( @@ -227,7 +230,6 @@ let PostCtrls = ({ postUri={post.uri} record={record} richText={richText} - showAppealLabelItem={showAppealLabelItem} style={styles.btnPad} hitSlop={big ? HITSLOP_20 : HITSLOP_10} /> diff --git a/src/view/com/util/post-embeds/QuoteEmbed.tsx b/src/view/com/util/post-embeds/QuoteEmbed.tsx index 35b091269..2b1c3e617 100644 --- a/src/view/com/util/post-embeds/QuoteEmbed.tsx +++ b/src/view/com/util/post-embeds/QuoteEmbed.tsx @@ -1,13 +1,15 @@ import React from 'react' import {StyleProp, StyleSheet, View, ViewStyle} from 'react-native' import { + AppBskyFeedDefs, AppBskyEmbedRecord, AppBskyFeedPost, AppBskyEmbedImages, AppBskyEmbedRecordWithMedia, - ModerationUI, AppBskyEmbedExternal, RichText as RichTextAPI, + moderatePost, + ModerationDecision, } from '@atproto/api' import {AtUri} from '@atproto/api' import {PostMeta} from '../PostMeta' @@ -16,20 +18,20 @@ import {Text} from '../text/Text' import {usePalette} from 'lib/hooks/usePalette' import {ComposerOptsQuote} from 'state/shell/composer' import {PostEmbeds} from '.' -import {PostAlerts} from '../moderation/PostAlerts' +import {PostAlerts} from '../../../../components/moderation/PostAlerts' import {makeProfileLink} from 'lib/routes/links' import {InfoCircleIcon} from 'lib/icons' import {Trans} from '@lingui/macro' +import {useModerationOpts} from '#/state/queries/preferences' +import {ContentHider} from '../../../../components/moderation/ContentHider' import {RichText} from '#/components/RichText' import {atoms as a} from '#/alf' export function MaybeQuoteEmbed({ embed, - moderation, style, }: { embed: AppBskyEmbedRecord.View - moderation: ModerationUI style?: StyleProp<ViewStyle> }) { const pal = usePalette('default') @@ -39,17 +41,9 @@ export function MaybeQuoteEmbed({ AppBskyFeedPost.validateRecord(embed.record.value).success ) { return ( - <QuoteEmbed - quote={{ - author: embed.record.author, - cid: embed.record.cid, - uri: embed.record.uri, - indexedAt: embed.record.indexedAt, - text: embed.record.value.text, - facets: embed.record.value.facets, - embeds: embed.record.embeds, - }} - moderation={moderation} + <QuoteEmbedModerated + viewRecord={embed.record} + postRecord={embed.record.value} style={style} /> ) @@ -75,19 +69,49 @@ export function MaybeQuoteEmbed({ return null } +function QuoteEmbedModerated({ + viewRecord, + postRecord, + style, +}: { + viewRecord: AppBskyEmbedRecord.ViewRecord + postRecord: AppBskyFeedPost.Record + style?: StyleProp<ViewStyle> +}) { + const moderationOpts = useModerationOpts() + const moderation = React.useMemo(() => { + return moderationOpts + ? moderatePost(viewRecordToPostView(viewRecord), moderationOpts) + : undefined + }, [viewRecord, moderationOpts]) + + const quote = { + author: viewRecord.author, + cid: viewRecord.cid, + uri: viewRecord.uri, + indexedAt: viewRecord.indexedAt, + text: postRecord.text, + facets: postRecord.facets, + embeds: viewRecord.embeds, + } + + return <QuoteEmbed quote={quote} moderation={moderation} style={style} /> +} + export function QuoteEmbed({ quote, moderation, style, }: { quote: ComposerOptsQuote - moderation?: ModerationUI + moderation?: ModerationDecision style?: StyleProp<ViewStyle> }) { const pal = usePalette('default') const itemUrip = new AtUri(quote.uri) const itemHref = makeProfileLink(quote.author, 'post', itemUrip.rkey) const itemTitle = `Post by ${quote.author.handle}` + const richText = React.useMemo( () => quote.text.trim() @@ -95,6 +119,7 @@ export function QuoteEmbed({ : undefined, [quote.text, quote.facets], ) + const embed = React.useMemo(() => { const e = quote.embeds?.[0] @@ -108,40 +133,52 @@ export function QuoteEmbed({ return e.media } }, [quote.embeds]) + return ( - <Link - style={[styles.container, pal.borderDark, style]} - hoverStyle={{borderColor: pal.colors.borderLinkHover}} - href={itemHref} - title={itemTitle}> - <View pointerEvents="none"> - <PostMeta - author={quote.author} - showAvatar - authorHasWarning={false} - postHref={itemHref} - timestamp={quote.indexedAt} - /> - </View> - {moderation ? ( - <PostAlerts moderation={moderation} style={styles.alert} /> - ) : null} - {richText ? ( - <RichText - enableTags - value={richText} - style={[a.text_md]} - numberOfLines={20} - disableLinks - authorHandle={quote.author.handle} - /> - ) : null} - {embed && <PostEmbeds embed={embed} moderation={{}} />} - </Link> + <ContentHider modui={moderation?.ui('contentList')}> + <Link + style={[styles.container, pal.borderDark, style]} + hoverStyle={{borderColor: pal.colors.borderLinkHover}} + href={itemHref} + title={itemTitle}> + <View pointerEvents="none"> + <PostMeta + author={quote.author} + moderation={moderation} + showAvatar + authorHasWarning={false} + postHref={itemHref} + timestamp={quote.indexedAt} + /> + </View> + {moderation ? ( + <PostAlerts modui={moderation.ui('contentView')} style={[a.py_xs]} /> + ) : null} + {richText ? ( + <RichText + value={richText} + style={[a.text_md]} + numberOfLines={20} + disableLinks + /> + ) : null} + {embed && <PostEmbeds embed={embed} moderation={moderation} />} + </Link> + </ContentHider> ) } -export default QuoteEmbed +function viewRecordToPostView( + viewRecord: AppBskyEmbedRecord.ViewRecord, +): AppBskyFeedDefs.PostView { + const {value, embeds, ...rest} = viewRecord + return { + ...rest, + $type: 'app.bsky.feed.defs#postView', + record: value, + embed: embeds?.[0], + } +} const styles = StyleSheet.create({ container: { diff --git a/src/view/com/util/post-embeds/index.tsx b/src/view/com/util/post-embeds/index.tsx index 7e235babb..47091fbb0 100644 --- a/src/view/com/util/post-embeds/index.tsx +++ b/src/view/com/util/post-embeds/index.tsx @@ -15,8 +15,7 @@ import { AppBskyEmbedRecordWithMedia, AppBskyFeedDefs, AppBskyGraphDefs, - ModerationUI, - PostModeration, + ModerationDecision, } from '@atproto/api' import {Link} from '../Link' import {ImageLayoutGrid} from '../images/ImageLayoutGrid' @@ -26,9 +25,8 @@ import {ExternalLinkEmbed} from './ExternalLinkEmbed' import {MaybeQuoteEmbed} from './QuoteEmbed' import {AutoSizedImage} from '../images/AutoSizedImage' import {ListEmbed} from './ListEmbed' -import {isCauseALabelOnUri, isQuoteBlurred} from 'lib/moderation' import {FeedSourceCard} from 'view/com/feeds/FeedSourceCard' -import {ContentHider} from '../moderation/ContentHider' +import {ContentHider} from '../../../../components/moderation/ContentHider' import {isNative} from '#/platform/detection' import {shareUrl} from '#/lib/sharing' @@ -42,12 +40,10 @@ type Embed = export function PostEmbeds({ embed, moderation, - moderationDecisions, style, }: { embed?: Embed - moderation: ModerationUI - moderationDecisions?: PostModeration['decisions'] + moderation?: ModerationDecision style?: StyleProp<ViewStyle> }) { const pal = usePalette('default') @@ -66,18 +62,10 @@ export function PostEmbeds({ // quote post with media // = if (AppBskyEmbedRecordWithMedia.isView(embed)) { - const isModOnQuote = - (AppBskyEmbedRecord.isViewRecord(embed.record.record) && - isCauseALabelOnUri(moderation.cause, embed.record.record.uri)) || - (moderationDecisions && isQuoteBlurred(moderationDecisions)) - const mediaModeration = isModOnQuote ? {} : moderation - const quoteModeration = isModOnQuote ? moderation : {} return ( <View style={style}> - <PostEmbeds embed={embed.media} moderation={mediaModeration} /> - <ContentHider moderation={quoteModeration}> - <MaybeQuoteEmbed embed={embed.record} moderation={quoteModeration} /> - </ContentHider> + <PostEmbeds embed={embed.media} moderation={moderation} /> + <MaybeQuoteEmbed embed={embed.record} /> </View> ) } @@ -86,6 +74,7 @@ export function PostEmbeds({ // custom feed embed (i.e. generator view) // = if (AppBskyFeedDefs.isGeneratorView(embed.record)) { + // TODO moderation return ( <FeedSourceCard feedUri={embed.record.uri} @@ -97,16 +86,13 @@ export function PostEmbeds({ // list embed if (AppBskyGraphDefs.isListView(embed.record)) { + // TODO moderation return <ListEmbed item={embed.record} /> } // quote post // = - return ( - <ContentHider moderation={moderation}> - <MaybeQuoteEmbed embed={embed} style={style} moderation={moderation} /> - </ContentHider> - ) + return <MaybeQuoteEmbed embed={embed} style={style} /> } // image embed @@ -132,35 +118,41 @@ export function PostEmbeds({ if (images.length === 1) { const {alt, thumb, aspectRatio} = images[0] return ( - <View style={[styles.imagesContainer, style]}> - <AutoSizedImage - alt={alt} - uri={thumb} - dimensionsHint={aspectRatio} - onPress={() => _openLightbox(0)} - onPressIn={() => onPressIn(0)} - style={[styles.singleImage]}> - {alt === '' ? null : ( - <View style={styles.altContainer}> - <Text style={styles.alt} accessible={false}> - ALT - </Text> - </View> - )} - </AutoSizedImage> - </View> + <ContentHider modui={moderation?.ui('contentMedia')}> + <View style={[styles.imagesContainer, style]}> + <AutoSizedImage + alt={alt} + uri={thumb} + dimensionsHint={aspectRatio} + onPress={() => _openLightbox(0)} + onPressIn={() => onPressIn(0)} + style={[styles.singleImage]}> + {alt === '' ? null : ( + <View style={styles.altContainer}> + <Text style={styles.alt} accessible={false}> + ALT + </Text> + </View> + )} + </AutoSizedImage> + </View> + </ContentHider> ) } return ( - <View style={[styles.imagesContainer, style]}> - <ImageLayoutGrid - images={embed.images} - onPress={_openLightbox} - onPressIn={onPressIn} - style={embed.images.length === 1 ? [styles.singleImage] : undefined} - /> - </View> + <ContentHider modui={moderation?.ui('contentMedia')}> + <View style={[styles.imagesContainer, style]}> + <ImageLayoutGrid + images={embed.images} + onPress={_openLightbox} + onPressIn={onPressIn} + style={ + embed.images.length === 1 ? [styles.singleImage] : undefined + } + /> + </View> + </ContentHider> ) } } @@ -171,15 +163,17 @@ export function PostEmbeds({ const link = embed.external return ( - <Link - asAnchor - anchorNoUnderline - href={link.uri} - style={[styles.extOuter, pal.view, pal.borderDark, style]} - hoverStyle={{borderColor: pal.colors.borderLinkHover}} - onLongPress={onShareExternal}> - <ExternalLinkEmbed link={link} /> - </Link> + <ContentHider modui={moderation?.ui('contentMedia')}> + <Link + asAnchor + anchorNoUnderline + href={link.uri} + style={[styles.extOuter, pal.view, pal.borderDark, style]} + hoverStyle={{borderColor: pal.colors.borderLinkHover}} + onLongPress={onShareExternal}> + <ExternalLinkEmbed link={link} /> + </Link> + </ContentHider> ) } diff --git a/src/view/screens/AppPasswords.tsx b/src/view/screens/AppPasswords.tsx index dc439c367..800216169 100644 --- a/src/view/screens/AppPasswords.tsx +++ b/src/view/screens/AppPasswords.tsx @@ -29,6 +29,8 @@ import { } from '#/state/queries/app-passwords' import {ErrorScreen} from '../com/util/error/ErrorScreen' import {cleanError} from '#/lib/strings/errors' +import * as Prompt from '#/components/Prompt' +import {useDialogControl} from '#/components/Dialog' type Props = NativeStackScreenProps<CommonNavigatorParams, 'AppPasswords'> export function AppPasswords({}: Props) { @@ -212,23 +214,18 @@ function AppPassword({ }) { const pal = usePalette('default') const {_} = useLingui() - const {openModal} = useModalControls() + const control = useDialogControl() const {contentLanguages} = useLanguagePrefs() const deleteMutation = useAppPasswordDeleteMutation() const onDelete = React.useCallback(async () => { - openModal({ - name: 'confirm', - title: _(msg`Delete app password`), - message: _( - msg`Are you sure you want to delete the app password "${name}"?`, - ), - async onPressConfirm() { - await deleteMutation.mutateAsync({name}) - Toast.show(_(msg`App password deleted`)) - }, - }) - }, [deleteMutation, openModal, name, _]) + await deleteMutation.mutateAsync({name}) + Toast.show(_(msg`App password deleted`)) + }, [deleteMutation, name, _]) + + const onPress = React.useCallback(() => { + control.open() + }, [control]) const primaryLocale = contentLanguages.length > 0 ? contentLanguages[0] : 'en-US' @@ -237,7 +234,7 @@ function AppPassword({ <TouchableOpacity testID={testID} style={[styles.item, pal.border]} - onPress={onDelete} + onPress={onPress} accessibilityRole="button" accessibilityLabel={_(msg`Delete app password`)} accessibilityHint=""> @@ -260,6 +257,17 @@ function AppPassword({ </Text> </View> <FontAwesomeIcon icon={['far', 'trash-can']} style={styles.trashIcon} /> + + <Prompt.Basic + control={control} + title={_(msg`Delete app password?`)} + description={_( + msg`Are you sure you want to delete the app password "${name}"?`, + )} + onConfirm={onDelete} + confirmButtonCta={_(msg`Delete`)} + confirmButtonColor="negative" + /> </TouchableOpacity> ) } diff --git a/src/view/screens/DebugMod.tsx b/src/view/screens/DebugMod.tsx new file mode 100644 index 000000000..64f2376a4 --- /dev/null +++ b/src/view/screens/DebugMod.tsx @@ -0,0 +1,923 @@ +import React from 'react' +import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types' +import {View} from 'react-native' +import { + LABELS, + mock, + moderatePost, + moderateProfile, + ModerationOpts, + AppBskyActorDefs, + AppBskyFeedDefs, + AppBskyFeedPost, + LabelPreference, + ModerationDecision, + ModerationBehavior, + RichText, + ComAtprotoLabelDefs, + interpretLabelValueDefinition, +} from '@atproto/api' +import {msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' +import {moderationOptsOverrideContext} from '#/state/queries/preferences' +import {useSession} from '#/state/session' +import {FeedNotification} from '#/state/queries/notifications/types' +import { + groupNotifications, + shouldFilterNotif, +} from '#/state/queries/notifications/util' + +import {atoms as a, useTheme} from '#/alf' +import {CenteredView, ScrollView} from '#/view/com/util/Views' +import {H1, H3, P, Text} from '#/components/Typography' +import {useGlobalLabelStrings} from '#/lib/moderation/useGlobalLabelStrings' +import * as Toggle from '#/components/forms/Toggle' +import * as ToggleButton from '#/components/forms/ToggleButton' +import {Button, ButtonIcon, ButtonText} from '#/components/Button' +import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check' +import { + ChevronBottom_Stroke2_Corner0_Rounded as ChevronBottom, + ChevronTop_Stroke2_Corner0_Rounded as ChevronTop, +} from '#/components/icons/Chevron' +import {ScreenHider} from '../../components/moderation/ScreenHider' +import {ProfileHeaderStandard} from '#/screens/Profile/Header/ProfileHeaderStandard' +import {ProfileCard} from '../com/profile/ProfileCard' +import {FeedItem} from '../com/posts/FeedItem' +import {FeedItem as NotifFeedItem} from '../com/notifications/FeedItem' +import {PostThreadItem} from '../com/post-thread/PostThreadItem' +import {Divider} from '#/components/Divider' + +const LABEL_VALUES: (keyof typeof LABELS)[] = Object.keys( + LABELS, +) as (keyof typeof LABELS)[] + +export const DebugModScreen = ({}: NativeStackScreenProps< + CommonNavigatorParams, + 'DebugMod' +>) => { + const t = useTheme() + const [scenario, setScenario] = React.useState<string[]>(['label']) + const [scenarioSwitches, setScenarioSwitches] = React.useState<string[]>([]) + const [label, setLabel] = React.useState<string[]>([LABEL_VALUES[0]]) + const [target, setTarget] = React.useState<string[]>(['account']) + const [visibility, setVisiblity] = React.useState<string[]>(['warn']) + const [customLabelDef, setCustomLabelDef] = + React.useState<ComAtprotoLabelDefs.LabelValueDefinition>({ + identifier: 'custom', + blurs: 'content', + severity: 'alert', + defaultSetting: 'warn', + locales: [ + { + lang: 'en', + name: 'Custom label', + description: 'A custom label created in this test environment', + }, + ], + }) + const [view, setView] = React.useState<string[]>(['post']) + const labelStrings = useGlobalLabelStrings() + const {currentAccount} = useSession() + + const isTargetMe = + scenario[0] === 'label' && scenarioSwitches.includes('targetMe') + const isSelfLabel = + scenario[0] === 'label' && scenarioSwitches.includes('selfLabel') + const noAdult = + scenario[0] === 'label' && scenarioSwitches.includes('noAdult') + const isLoggedOut = + scenario[0] === 'label' && scenarioSwitches.includes('loggedOut') + const isFollowing = scenarioSwitches.includes('following') + + const did = + isTargetMe && currentAccount ? currentAccount.did : 'did:web:bob.test' + + const profile = React.useMemo(() => { + const mockedProfile = mock.profileViewBasic({ + handle: `bob.test`, + displayName: 'Bob Robertson', + description: 'User with this as their bio', + labels: + scenario[0] === 'label' && target[0] === 'account' + ? [ + mock.label({ + src: isSelfLabel ? did : undefined, + val: label[0], + uri: `at://${did}/`, + }), + ] + : scenario[0] === 'label' && target[0] === 'profile' + ? [ + mock.label({ + src: isSelfLabel ? did : undefined, + val: label[0], + uri: `at://${did}/app.bsky.actor.profile/self`, + }), + ] + : undefined, + viewer: mock.actorViewerState({ + following: isFollowing + ? `at://${currentAccount?.did || ''}/app.bsky.graph.follow/1234` + : undefined, + muted: scenario[0] === 'mute', + mutedByList: undefined, + blockedBy: undefined, + blocking: + scenario[0] === 'block' + ? `at://did:web:alice.test/app.bsky.actor.block/fake` + : undefined, + blockingByList: undefined, + }), + }) + mockedProfile.did = did + mockedProfile.avatar = 'https://bsky.social/about/images/favicon-32x32.png' + mockedProfile.banner = + 'https://bsky.social/about/images/social-card-default-gradient.png' + return mockedProfile + }, [scenario, target, label, isSelfLabel, did, isFollowing, currentAccount]) + + const post = React.useMemo(() => { + return mock.postView({ + record: mock.post({ + text: "This is the body of the post. It's where the text goes. You get the idea.", + }), + author: profile, + labels: + scenario[0] === 'label' && target[0] === 'post' + ? [ + mock.label({ + src: isSelfLabel ? did : undefined, + val: label[0], + uri: `at://${did}/app.bsky.feed.post/fake`, + }), + ] + : undefined, + embed: + target[0] === 'embed' + ? mock.embedRecordView({ + record: mock.post({ + text: 'Embed', + }), + labels: + scenario[0] === 'label' && target[0] === 'embed' + ? [ + mock.label({ + src: isSelfLabel ? did : undefined, + val: label[0], + uri: `at://${did}/app.bsky.feed.post/fake`, + }), + ] + : undefined, + author: profile, + }) + : { + $type: 'app.bsky.embed.images#view', + images: [ + { + thumb: + 'https://bsky.social/about/images/social-card-default-gradient.png', + fullsize: + 'https://bsky.social/about/images/social-card-default-gradient.png', + alt: '', + }, + ], + }, + }) + }, [scenario, label, target, profile, isSelfLabel, did]) + + const replyNotif = React.useMemo(() => { + const notif = mock.replyNotification({ + record: mock.post({ + text: "This is the body of the post. It's where the text goes. You get the idea.", + reply: { + parent: { + uri: `at://${did}/app.bsky.feed.post/fake-parent`, + cid: 'bafyreiclp443lavogvhj3d2ob2cxbfuscni2k5jk7bebjzg7khl3esabwq', + }, + root: { + uri: `at://${did}/app.bsky.feed.post/fake-parent`, + cid: 'bafyreiclp443lavogvhj3d2ob2cxbfuscni2k5jk7bebjzg7khl3esabwq', + }, + }, + }), + author: profile, + labels: + scenario[0] === 'label' && target[0] === 'post' + ? [ + mock.label({ + src: isSelfLabel ? did : undefined, + val: label[0], + uri: `at://${did}/app.bsky.feed.post/fake`, + }), + ] + : undefined, + }) + const [item] = groupNotifications([notif]) + item.subject = mock.postView({ + record: notif.record as AppBskyFeedPost.Record, + author: profile, + labels: notif.labels, + }) + return item + }, [scenario, label, target, profile, isSelfLabel, did]) + + const followNotif = React.useMemo(() => { + const notif = mock.followNotification({ + author: profile, + subjectDid: currentAccount?.did || '', + }) + const [item] = groupNotifications([notif]) + return item + }, [profile, currentAccount]) + + const modOpts = React.useMemo(() => { + return { + userDid: isLoggedOut ? '' : isTargetMe ? did : 'did:web:alice.test', + prefs: { + adultContentEnabled: !noAdult, + labels: { + [label[0]]: visibility[0] as LabelPreference, + }, + labelers: [ + { + did: 'did:plc:fake-labeler', + labels: {[label[0]]: visibility[0] as LabelPreference}, + }, + ], + mutedWords: [], + hiddenPosts: [], + }, + labelDefs: { + 'did:plc:fake-labeler': [ + interpretLabelValueDefinition(customLabelDef, 'did:plc:fake-labeler'), + ], + }, + } + }, [label, visibility, noAdult, isLoggedOut, isTargetMe, did, customLabelDef]) + + const profileModeration = React.useMemo(() => { + return moderateProfile(profile, modOpts) + }, [profile, modOpts]) + const postModeration = React.useMemo(() => { + return moderatePost(post, modOpts) + }, [post, modOpts]) + + return ( + <moderationOptsOverrideContext.Provider value={modOpts}> + <ScrollView> + <CenteredView style={[t.atoms.bg, a.px_lg, a.py_lg]}> + <H1 style={[a.text_5xl, a.font_bold, a.pb_lg]}>Moderation states</H1> + + <Heading title="" subtitle="Scenario" /> + <ToggleButton.Group + label="Scenario" + values={scenario} + onChange={setScenario}> + <ToggleButton.Button name="label" label="Label"> + Label + </ToggleButton.Button> + <ToggleButton.Button name="block" label="Block"> + Block + </ToggleButton.Button> + <ToggleButton.Button name="mute" label="Mute"> + Mute + </ToggleButton.Button> + </ToggleButton.Group> + + {scenario[0] === 'label' && ( + <> + <View + style={[ + a.border, + a.rounded_sm, + a.mt_lg, + a.mb_lg, + a.p_lg, + t.atoms.border_contrast_medium, + ]}> + <Toggle.Group + label="Toggle" + type="radio" + values={label} + onChange={setLabel}> + <View style={[a.flex_row, a.gap_md, a.flex_wrap]}> + {LABEL_VALUES.map(labelValue => { + let targetFixed = target[0] + if ( + targetFixed !== 'account' && + targetFixed !== 'profile' + ) { + targetFixed = 'content' + } + const disabled = + isSelfLabel && + LABELS[labelValue].flags.includes('no-self') + return ( + <Toggle.Item + key={labelValue} + name={labelValue} + label={labelStrings[labelValue].name} + disabled={disabled} + style={disabled ? {opacity: 0.5} : undefined}> + <Toggle.Radio /> + <Toggle.Label>{labelValue}</Toggle.Label> + </Toggle.Item> + ) + })} + <Toggle.Item + name="custom" + label="Custom label" + disabled={isSelfLabel} + style={isSelfLabel ? {opacity: 0.5} : undefined}> + <Toggle.Radio /> + <Toggle.Label>Custom label</Toggle.Label> + </Toggle.Item> + </View> + </Toggle.Group> + + {label[0] === 'custom' ? ( + <CustomLabelForm + def={customLabelDef} + setDef={setCustomLabelDef} + /> + ) : ( + <> + <View style={{height: 10}} /> + <Divider /> + </> + )} + + <View style={{height: 10}} /> + + <SmallToggler label="Advanced"> + <Toggle.Group + label="Toggle" + type="checkbox" + values={scenarioSwitches} + onChange={setScenarioSwitches}> + <View style={[a.gap_md, a.flex_row, a.flex_wrap, a.pt_md]}> + <Toggle.Item name="targetMe" label="Target is me"> + <Toggle.Checkbox /> + <Toggle.Label>Target is me</Toggle.Label> + </Toggle.Item> + <Toggle.Item name="following" label="Following target"> + <Toggle.Checkbox /> + <Toggle.Label>Following target</Toggle.Label> + </Toggle.Item> + <Toggle.Item name="selfLabel" label="Self label"> + <Toggle.Checkbox /> + <Toggle.Label>Self label</Toggle.Label> + </Toggle.Item> + <Toggle.Item name="noAdult" label="Adult disabled"> + <Toggle.Checkbox /> + <Toggle.Label>Adult disabled</Toggle.Label> + </Toggle.Item> + <Toggle.Item name="loggedOut" label="Logged out"> + <Toggle.Checkbox /> + <Toggle.Label>Logged out</Toggle.Label> + </Toggle.Item> + </View> + </Toggle.Group> + + {LABELS[label[0] as keyof typeof LABELS]?.configurable !== + false && ( + <View style={[a.mt_md]}> + <Text + style={[a.font_bold, a.text_xs, t.atoms.text, a.pb_sm]}> + Preference + </Text> + <Toggle.Group + label="Preference" + type="radio" + values={visibility} + onChange={setVisiblity}> + <View + style={[ + a.flex_row, + a.gap_md, + a.flex_wrap, + a.align_center, + ]}> + <Toggle.Item name="hide" label="Hide"> + <Toggle.Radio /> + <Toggle.Label>Hide</Toggle.Label> + </Toggle.Item> + <Toggle.Item name="warn" label="Warn"> + <Toggle.Radio /> + <Toggle.Label>Warn</Toggle.Label> + </Toggle.Item> + <Toggle.Item name="ignore" label="Ignore"> + <Toggle.Radio /> + <Toggle.Label>Ignore</Toggle.Label> + </Toggle.Item> + </View> + </Toggle.Group> + </View> + )} + </SmallToggler> + </View> + + <View style={[a.flex_row, a.flex_wrap, a.gap_md]}> + <View> + <Text + style={[ + a.font_bold, + a.text_xs, + t.atoms.text, + a.pl_md, + a.pb_xs, + ]}> + Target + </Text> + <View + style={[ + a.border, + a.rounded_full, + a.px_md, + a.py_sm, + t.atoms.border_contrast_medium, + t.atoms.bg, + ]}> + <Toggle.Group + label="Target" + type="radio" + values={target} + onChange={setTarget}> + <View style={[a.flex_row, a.gap_md, a.flex_wrap]}> + <Toggle.Item name="account" label="Account"> + <Toggle.Radio /> + <Toggle.Label>Account</Toggle.Label> + </Toggle.Item> + <Toggle.Item name="profile" label="Profile"> + <Toggle.Radio /> + <Toggle.Label>Profile</Toggle.Label> + </Toggle.Item> + <Toggle.Item name="post" label="Post"> + <Toggle.Radio /> + <Toggle.Label>Post</Toggle.Label> + </Toggle.Item> + <Toggle.Item name="embed" label="Embed"> + <Toggle.Radio /> + <Toggle.Label>Embed</Toggle.Label> + </Toggle.Item> + </View> + </Toggle.Group> + </View> + </View> + </View> + </> + )} + + <Spacer /> + + <Heading title="" subtitle="Results" /> + + <ToggleButton.Group label="Results" values={view} onChange={setView}> + <ToggleButton.Button name="post" label="Post"> + Post + </ToggleButton.Button> + <ToggleButton.Button name="notifications" label="Notifications"> + Notifications + </ToggleButton.Button> + <ToggleButton.Button name="account" label="Account"> + Account + </ToggleButton.Button> + <ToggleButton.Button name="data" label="Data"> + Data + </ToggleButton.Button> + </ToggleButton.Group> + + <View + style={[ + a.border, + a.rounded_sm, + a.mt_lg, + a.p_md, + t.atoms.border_contrast_medium, + ]}> + {view[0] === 'post' && ( + <> + <Heading title="Post" subtitle="in feed" /> + <MockPostFeedItem post={post} moderation={postModeration} /> + + <Heading title="Post" subtitle="viewed directly" /> + <MockPostThreadItem post={post} moderation={postModeration} /> + + <Heading title="Post" subtitle="reply in thread" /> + <MockPostThreadItem + post={post} + moderation={postModeration} + reply + /> + </> + )} + + {view[0] === 'notifications' && ( + <> + <Heading title="Notification" subtitle="quote or reply" /> + <MockNotifItem notif={replyNotif} moderationOpts={modOpts} /> + <View style={{height: 20}} /> + <Heading title="Notification" subtitle="follow or like" /> + <MockNotifItem notif={followNotif} moderationOpts={modOpts} /> + </> + )} + + {view[0] === 'account' && ( + <> + <Heading title="Account" subtitle="in listing" /> + <MockAccountCard + profile={profile} + moderation={profileModeration} + /> + + <Heading title="Account" subtitle="viewing directly" /> + <MockAccountScreen + profile={profile} + moderation={profileModeration} + moderationOpts={modOpts} + /> + </> + )} + + {view[0] === 'data' && ( + <> + <ModerationUIView + label="Profile Moderation UI" + mod={profileModeration} + /> + <ModerationUIView + label="Post Moderation UI" + mod={postModeration} + /> + <DataView + label={label[0]} + data={LABELS[label[0] as keyof typeof LABELS]} + /> + <DataView + label="Profile Moderation Data" + data={profileModeration} + /> + <DataView label="Post Moderation Data" data={postModeration} /> + </> + )} + </View> + + <View style={{height: 400}} /> + </CenteredView> + </ScrollView> + </moderationOptsOverrideContext.Provider> + ) +} + +function Heading({title, subtitle}: {title: string; subtitle?: string}) { + const t = useTheme() + return ( + <H3 style={[a.text_3xl, a.font_bold, a.pb_md]}> + {title}{' '} + {!!subtitle && ( + <H3 style={[t.atoms.text_contrast_medium, a.text_lg]}>{subtitle}</H3> + )} + </H3> + ) +} + +function CustomLabelForm({ + def, + setDef, +}: { + def: ComAtprotoLabelDefs.LabelValueDefinition + setDef: React.Dispatch< + React.SetStateAction<ComAtprotoLabelDefs.LabelValueDefinition> + > +}) { + const t = useTheme() + return ( + <View + style={[ + a.flex_row, + a.flex_wrap, + a.gap_md, + t.atoms.bg_contrast_25, + a.rounded_md, + a.p_md, + a.mt_md, + ]}> + <View> + <Text style={[a.font_bold, a.text_xs, t.atoms.text, a.pl_md, a.pb_xs]}> + Blurs + </Text> + <View + style={[ + a.border, + a.rounded_full, + a.px_md, + a.py_sm, + t.atoms.border_contrast_medium, + t.atoms.bg, + ]}> + <Toggle.Group + label="Blurs" + type="radio" + values={[def.blurs]} + onChange={values => setDef(v => ({...v, blurs: values[0]}))}> + <View style={[a.flex_row, a.gap_md, a.flex_wrap]}> + <Toggle.Item name="content" label="Content"> + <Toggle.Radio /> + <Toggle.Label>Content</Toggle.Label> + </Toggle.Item> + <Toggle.Item name="media" label="Media"> + <Toggle.Radio /> + <Toggle.Label>Media</Toggle.Label> + </Toggle.Item> + <Toggle.Item name="none" label="None"> + <Toggle.Radio /> + <Toggle.Label>None</Toggle.Label> + </Toggle.Item> + </View> + </Toggle.Group> + </View> + </View> + <View> + <Text style={[a.font_bold, a.text_xs, t.atoms.text, a.pl_md, a.pb_xs]}> + Severity + </Text> + <View + style={[ + a.border, + a.rounded_full, + a.px_md, + a.py_sm, + t.atoms.border_contrast_medium, + t.atoms.bg, + ]}> + <Toggle.Group + label="Severity" + type="radio" + values={[def.severity]} + onChange={values => setDef(v => ({...v, severity: values[0]}))}> + <View style={[a.flex_row, a.gap_md, a.flex_wrap, a.align_center]}> + <Toggle.Item name="alert" label="Alert"> + <Toggle.Radio /> + <Toggle.Label>Alert</Toggle.Label> + </Toggle.Item> + <Toggle.Item name="inform" label="Inform"> + <Toggle.Radio /> + <Toggle.Label>Inform</Toggle.Label> + </Toggle.Item> + <Toggle.Item name="none" label="None"> + <Toggle.Radio /> + <Toggle.Label>None</Toggle.Label> + </Toggle.Item> + </View> + </Toggle.Group> + </View> + </View> + </View> + ) +} + +function Toggler({label, children}: React.PropsWithChildren<{label: string}>) { + const t = useTheme() + const [show, setShow] = React.useState(false) + return ( + <View style={a.mb_md}> + <View + style={[ + t.atoms.border_contrast_medium, + a.border, + a.rounded_sm, + a.p_xs, + ]}> + <Button + variant="solid" + color="secondary" + label="Toggle visibility" + size="small" + onPress={() => setShow(!show)}> + <ButtonText>{label}</ButtonText> + <ButtonIcon + icon={show ? ChevronTop : ChevronBottom} + position="right" + /> + </Button> + {show && children} + </View> + </View> + ) +} + +function SmallToggler({ + label, + children, +}: React.PropsWithChildren<{label: string}>) { + const [show, setShow] = React.useState(false) + return ( + <View> + <View style={[a.flex_row]}> + <Button + variant="ghost" + color="secondary" + label="Toggle visibility" + size="tiny" + onPress={() => setShow(!show)}> + <ButtonText>{label}</ButtonText> + <ButtonIcon + icon={show ? ChevronTop : ChevronBottom} + position="right" + /> + </Button> + </View> + {show && children} + </View> + ) +} + +function DataView({label, data}: {label: string; data: any}) { + return ( + <Toggler label={label}> + <Text style={[{fontFamily: 'monospace'}, a.p_md]}> + {JSON.stringify(data, null, 2)} + </Text> + </Toggler> + ) +} + +function ModerationUIView({ + mod, + label, +}: { + mod: ModerationDecision + label: string +}) { + return ( + <Toggler label={label}> + <View style={a.p_lg}> + {[ + 'profileList', + 'profileView', + 'avatar', + 'banner', + 'displayName', + 'contentList', + 'contentView', + 'contentMedia', + ].map(key => { + const ui = mod.ui(key as keyof ModerationBehavior) + return ( + <View key={key} style={[a.flex_row, a.gap_md]}> + <Text style={[a.font_bold, {width: 100}]}>{key}</Text> + <Flag v={ui.filter} label="Filter" /> + <Flag v={ui.blur} label="Blur" /> + <Flag v={ui.alert} label="Alert" /> + <Flag v={ui.inform} label="Inform" /> + <Flag v={ui.noOverride} label="No-override" /> + </View> + ) + })} + </View> + </Toggler> + ) +} + +function Spacer() { + return <View style={{height: 30}} /> +} + +function MockPostFeedItem({ + post, + moderation, +}: { + post: AppBskyFeedDefs.PostView + moderation: ModerationDecision +}) { + const t = useTheme() + if (moderation.ui('contentList').filter) { + return ( + <P style={[t.atoms.bg_contrast_25, a.px_lg, a.py_md, a.mb_lg]}> + Filtered from the feed + </P> + ) + } + return ( + <FeedItem + post={post} + record={post.record as AppBskyFeedPost.Record} + moderation={moderation} + reason={undefined} + /> + ) +} + +function MockPostThreadItem({ + post, + reply, +}: { + post: AppBskyFeedDefs.PostView + moderation: ModerationDecision + reply?: boolean +}) { + return ( + <PostThreadItem + // @ts-ignore + post={post} + record={post.record as AppBskyFeedPost.Record} + depth={reply ? 1 : 0} + isHighlightedPost={!reply} + treeView={false} + prevPost={undefined} + nextPost={undefined} + hasPrecedingItem={false} + onPostReply={() => {}} + /> + ) +} + +function MockNotifItem({ + notif, + moderationOpts, +}: { + notif: FeedNotification + moderationOpts: ModerationOpts +}) { + const t = useTheme() + if (shouldFilterNotif(notif.notification, moderationOpts)) { + return ( + <P style={[t.atoms.bg_contrast_25, a.px_lg, a.py_md]}> + Filtered from the feed + </P> + ) + } + return <NotifFeedItem item={notif} moderationOpts={moderationOpts} /> +} + +function MockAccountCard({ + profile, + moderation, +}: { + profile: AppBskyActorDefs.ProfileViewBasic + moderation: ModerationDecision +}) { + const t = useTheme() + + if (moderation.ui('profileList').filter) { + return ( + <P style={[t.atoms.bg_contrast_25, a.px_lg, a.py_md, a.mb_lg]}> + Filtered from the listing + </P> + ) + } + + return <ProfileCard profile={profile} /> +} + +function MockAccountScreen({ + profile, + moderation, + moderationOpts, +}: { + profile: AppBskyActorDefs.ProfileViewBasic + moderation: ModerationDecision + moderationOpts: ModerationOpts +}) { + const t = useTheme() + const {_} = useLingui() + return ( + <View style={[t.atoms.border_contrast_medium, a.border, a.mb_md]}> + <ScreenHider + style={{}} + screenDescription={_(msg`profile`)} + modui={moderation.ui('profileView')}> + <ProfileHeaderStandard + // @ts-ignore ProfileViewBasic is close enough -prf + profile={profile} + moderationOpts={moderationOpts} + descriptionRT={new RichText({text: profile.description as string})} + /> + </ScreenHider> + </View> + ) +} + +function Flag({v, label}: {v: boolean | undefined; label: string}) { + const t = useTheme() + return ( + <View style={[a.flex_row, a.align_center, a.gap_xs]}> + <View + style={[ + a.justify_center, + a.align_center, + a.rounded_xs, + a.border, + t.atoms.border_contrast_medium, + { + backgroundColor: t.palette.contrast_25, + width: 14, + height: 14, + }, + ]}> + {v && <Check size="xs" fill={t.palette.contrast_900} />} + </View> + <P style={a.text_xs}>{label}</P> + </View> + ) +} diff --git a/src/view/screens/LanguageSettings.tsx b/src/view/screens/LanguageSettings.tsx index 819840a46..b86cd46e1 100644 --- a/src/view/screens/LanguageSettings.tsx +++ b/src/view/screens/LanguageSettings.tsx @@ -97,7 +97,7 @@ export function LanguageSettingsScreen(_props: Props) { <Text style={[pal.text, s.pb10]}> <Trans> Select your app language for the default text to display in the - app + app. </Trans> </Text> @@ -296,7 +296,7 @@ export function LanguageSettingsScreen(_props: Props) { type="button" style={[pal.text, {flexShrink: 1, overflow: 'hidden'}]} numberOfLines={1}> - {myLanguages.length ? myLanguages : 'Select languages'} + {myLanguages.length ? myLanguages : _(msg`Select languages`)} </Text> </Button> </View> diff --git a/src/view/screens/Moderation.tsx b/src/view/screens/Moderation.tsx deleted file mode 100644 index 928766c30..000000000 --- a/src/view/screens/Moderation.tsx +++ /dev/null @@ -1,304 +0,0 @@ -import React from 'react' -import { - ActivityIndicator, - StyleSheet, - TouchableOpacity, - View, -} from 'react-native' -import {useFocusEffect} from '@react-navigation/native' -import { - FontAwesomeIcon, - FontAwesomeIconStyle, -} from '@fortawesome/react-native-fontawesome' -import {ComAtprotoLabelDefs} from '@atproto/api' -import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types' -import {s} from 'lib/styles' -import {CenteredView} from '../com/util/Views' -import {ViewHeader} from '../com/util/ViewHeader' -import {Link, TextLink} from '../com/util/Link' -import {Text} from '../com/util/text/Text' -import {usePalette} from 'lib/hooks/usePalette' -import {useAnalytics} from 'lib/analytics/analytics' -import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' -import {useSetMinimalShellMode} from '#/state/shell' -import {useModalControls} from '#/state/modals' -import {Trans, msg} from '@lingui/macro' -import {useLingui} from '@lingui/react' -import {ToggleButton} from '../com/util/forms/ToggleButton' -import {useSession} from '#/state/session' -import { - useProfileQuery, - useProfileUpdateMutation, -} from '#/state/queries/profile' -import {ScrollView} from '../com/util/Views' -import {useGlobalDialogsControlContext} from '#/components/dialogs/Context' - -type Props = NativeStackScreenProps<CommonNavigatorParams, 'Moderation'> -export function ModerationScreen({}: Props) { - const pal = usePalette('default') - const {_} = useLingui() - const setMinimalShellMode = useSetMinimalShellMode() - const {screen, track} = useAnalytics() - const {isTabletOrDesktop} = useWebMediaQueries() - const {openModal} = useModalControls() - const {mutedWordsDialogControl} = useGlobalDialogsControlContext() - - useFocusEffect( - React.useCallback(() => { - screen('Moderation') - setMinimalShellMode(false) - }, [screen, setMinimalShellMode]), - ) - - const onPressContentFiltering = React.useCallback(() => { - track('Moderation:ContentfilteringButtonClicked') - openModal({name: 'content-filtering-settings'}) - }, [track, openModal]) - - return ( - <CenteredView - style={[ - s.hContentRegion, - pal.border, - isTabletOrDesktop ? styles.desktopContainer : pal.viewLight, - ]} - testID="moderationScreen"> - <ViewHeader title={_(msg`Moderation`)} showOnDesktop /> - <ScrollView contentContainerStyle={[styles.noBorder]}> - <View style={styles.spacer} /> - <TouchableOpacity - testID="contentFilteringBtn" - style={[styles.linkCard, pal.view]} - onPress={onPressContentFiltering} - accessibilityRole="tab" - accessibilityHint="" - accessibilityLabel={_(msg`Open content filtering settings`)}> - <View style={[styles.iconContainer, pal.btn]}> - <FontAwesomeIcon - icon="eye" - style={pal.text as FontAwesomeIconStyle} - /> - </View> - <Text type="lg" style={pal.text}> - <Trans>Content filtering</Trans> - </Text> - </TouchableOpacity> - <TouchableOpacity - testID="mutedWordsBtn" - style={[styles.linkCard, pal.view]} - onPress={() => mutedWordsDialogControl.open()} - accessibilityRole="tab" - accessibilityHint="" - accessibilityLabel={_(msg`Open muted words settings`)}> - <View style={[styles.iconContainer, pal.btn]}> - <FontAwesomeIcon - icon="filter" - style={pal.text as FontAwesomeIconStyle} - /> - </View> - <Text type="lg" style={pal.text}> - <Trans>Muted words & tags</Trans> - </Text> - </TouchableOpacity> - <Link - testID="moderationlistsBtn" - style={[styles.linkCard, pal.view]} - href="/moderation/modlists"> - <View style={[styles.iconContainer, pal.btn]}> - <FontAwesomeIcon - icon="users-slash" - style={pal.text as FontAwesomeIconStyle} - /> - </View> - <Text type="lg" style={pal.text}> - <Trans>Moderation lists</Trans> - </Text> - </Link> - <Link - testID="mutedAccountsBtn" - style={[styles.linkCard, pal.view]} - href="/moderation/muted-accounts"> - <View style={[styles.iconContainer, pal.btn]}> - <FontAwesomeIcon - icon="user-slash" - style={pal.text as FontAwesomeIconStyle} - /> - </View> - <Text type="lg" style={pal.text}> - <Trans>Muted accounts</Trans> - </Text> - </Link> - <Link - testID="blockedAccountsBtn" - style={[styles.linkCard, pal.view]} - href="/moderation/blocked-accounts"> - <View style={[styles.iconContainer, pal.btn]}> - <FontAwesomeIcon - icon="ban" - style={pal.text as FontAwesomeIconStyle} - /> - </View> - <Text type="lg" style={pal.text}> - <Trans>Blocked accounts</Trans> - </Text> - </Link> - <Text - type="xl-bold" - style={[ - pal.text, - { - paddingHorizontal: 18, - paddingTop: 18, - paddingBottom: 6, - }, - ]}> - <Trans>Logged-out visibility</Trans> - </Text> - <PwiOptOut /> - </ScrollView> - </CenteredView> - ) -} - -function PwiOptOut() { - const pal = usePalette('default') - const {_} = useLingui() - const {currentAccount} = useSession() - const {data: profile} = useProfileQuery({did: currentAccount?.did}) - const updateProfile = useProfileUpdateMutation() - - const isOptedOut = - profile?.labels?.some(l => l.val === '!no-unauthenticated') || false - const canToggle = profile && !updateProfile.isPending - - const onToggleOptOut = React.useCallback(() => { - if (!profile) { - return - } - let wasAdded = false - updateProfile.mutate({ - profile, - updates: existing => { - // create labels attr if needed - existing.labels = ComAtprotoLabelDefs.isSelfLabels(existing.labels) - ? existing.labels - : { - $type: 'com.atproto.label.defs#selfLabels', - values: [], - } - - // toggle the label - const hasLabel = existing.labels.values.some( - l => l.val === '!no-unauthenticated', - ) - if (hasLabel) { - wasAdded = false - existing.labels.values = existing.labels.values.filter( - l => l.val !== '!no-unauthenticated', - ) - } else { - wasAdded = true - existing.labels.values.push({val: '!no-unauthenticated'}) - } - - // delete if no longer needed - if (existing.labels.values.length === 0) { - delete existing.labels - } - return existing - }, - checkCommitted: res => { - const exists = !!res.data.labels?.some( - l => l.val === '!no-unauthenticated', - ) - return exists === wasAdded - }, - }) - }, [updateProfile, profile]) - - return ( - <View style={[pal.view, styles.toggleCard]}> - <View - style={{flexDirection: 'row', alignItems: 'center', paddingRight: 14}}> - <ToggleButton - type="default-light" - label={_( - msg`Discourage apps from showing my account to logged-out users`, - )} - labelType="lg" - isSelected={isOptedOut} - onPress={canToggle ? onToggleOptOut : undefined} - style={[canToggle ? undefined : {opacity: 0.5}, {flex: 1}]} - /> - {updateProfile.isPending && <ActivityIndicator />} - </View> - <View - style={{ - flexDirection: 'column', - gap: 10, - paddingLeft: 66, - paddingRight: 12, - paddingBottom: 10, - marginBottom: 64, - }}> - <Text style={pal.textLight}> - <Trans> - Bluesky will not show your profile and posts to logged-out users. - Other apps may not honor this request. This does not make your - account private. - </Trans> - </Text> - <Text style={[pal.textLight, {fontWeight: '500'}]}> - <Trans> - Note: Bluesky is an open and public network. This setting only - limits the visibility of your content on the Bluesky app and - website, and other apps may not respect this setting. Your content - may still be shown to logged-out users by other apps and websites. - </Trans> - </Text> - <TextLink - style={pal.link} - href="https://blueskyweb.zendesk.com/hc/en-us/articles/15835264007693-Data-Privacy" - text={_(msg`Learn more about what is public on Bluesky.`)} - /> - </View> - </View> - ) -} - -const styles = StyleSheet.create({ - desktopContainer: { - borderLeftWidth: 1, - borderRightWidth: 1, - }, - spacer: { - height: 6, - }, - linkCard: { - flexDirection: 'row', - alignItems: 'center', - paddingVertical: 12, - paddingHorizontal: 18, - marginBottom: 1, - }, - toggleCard: { - paddingVertical: 8, - paddingTop: 2, - paddingHorizontal: 6, - marginBottom: 1, - }, - iconContainer: { - alignItems: 'center', - justifyContent: 'center', - width: 40, - height: 40, - borderRadius: 30, - marginRight: 12, - }, - noBorder: { - borderBottomWidth: 0, - borderRightWidth: 0, - borderLeftWidth: 0, - borderTopWidth: 0, - }, -}) diff --git a/src/view/screens/NotFound.tsx b/src/view/screens/NotFound.tsx index dfa840abb..7d51619b3 100644 --- a/src/view/screens/NotFound.tsx +++ b/src/view/screens/NotFound.tsx @@ -51,7 +51,13 @@ export const NotFoundScreen = () => { </Text> <Button type="primary" - label={canGoBack ? 'Go back' : 'Go home'} + label={canGoBack ? _(msg`Go Back`) : _(msg`Go Home`)} + accessibilityLabel={canGoBack ? _(msg`Go back`) : _(msg`Go home`)} + accessibilityHint={ + canGoBack + ? _(msg`Returns to previous page`) + : _(msg`Returns to home page`) + } onPress={onPressHome} /> </View> diff --git a/src/view/screens/PostThread.tsx b/src/view/screens/PostThread.tsx index aa09ab9ed..ba1fa130e 100644 --- a/src/view/screens/PostThread.tsx +++ b/src/view/screens/PostThread.tsx @@ -59,11 +59,7 @@ export function PostThreadScreen({route}: Props) { uri: thread.post.uri, cid: thread.post.cid, text: thread.record.text, - author: { - handle: thread.post.author.handle, - displayName: thread.post.author.displayName, - avatar: thread.post.author.avatar, - }, + author: thread.post.author, embed: thread.post.embed, }, onPost: () => diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx index b30b4491b..d5a46c5c9 100644 --- a/src/view/screens/Profile.tsx +++ b/src/view/screens/Profile.tsx @@ -1,5 +1,5 @@ import React, {useMemo} from 'react' -import {StyleSheet, View} from 'react-native' +import {StyleSheet} from 'react-native' import {useFocusEffect} from '@react-navigation/native' import { AppBskyActorDefs, @@ -7,48 +7,39 @@ import { ModerationOpts, RichText as RichTextAPI, } from '@atproto/api' -import {msg, Trans} from '@lingui/macro' +import {msg} from '@lingui/macro' import {useLingui} from '@lingui/react' import {NativeStackScreenProps, CommonNavigatorParams} from 'lib/routes/types' import {CenteredView} from '../com/util/Views' import {ListRef} from '../com/util/List' -import {ScreenHider} from 'view/com/util/moderation/ScreenHider' -import {Feed} from 'view/com/posts/Feed' +import {ScreenHider} from '#/components/moderation/ScreenHider' import {ProfileLists} from '../com/lists/ProfileLists' import {ProfileFeedgens} from '../com/feeds/ProfileFeedgens' -import {ProfileHeader, ProfileHeaderLoading} from '../com/profile/ProfileHeader' import {PagerWithHeader} from 'view/com/pager/PagerWithHeader' import {ErrorScreen} from '../com/util/error/ErrorScreen' -import {EmptyState} from '../com/util/EmptyState' import {FAB} from '../com/util/fab/FAB' import {s, colors} from 'lib/styles' import {useAnalytics} from 'lib/analytics/analytics' import {ComposeIcon2} from 'lib/icons' import {useSetTitle} from 'lib/hooks/useSetTitle' import {combinedDisplayName} from 'lib/strings/display-names' -import { - FeedDescriptor, - resetProfilePostsQueries, -} from '#/state/queries/post-feed' +import {resetProfilePostsQueries} from '#/state/queries/post-feed' import {useResolveDidQuery} from '#/state/queries/resolve-uri' import {useProfileQuery} from '#/state/queries/profile' import {useProfileShadow} from '#/state/cache/profile-shadow' import {useSession, getAgent} from '#/state/session' import {useModerationOpts} from '#/state/queries/preferences' -import {useProfileExtraInfoQuery} from '#/state/queries/profile-extra-info' -import {RQKEY as FEED_RQKEY} from '#/state/queries/post-feed' +import {useLabelerInfoQuery} from '#/state/queries/labeler' import {useSetDrawerSwipeDisabled, useSetMinimalShellMode} from '#/state/shell' import {cleanError} from '#/lib/strings/errors' -import {LoadLatestBtn} from '../com/util/load-latest/LoadLatestBtn' -import {useQueryClient} from '@tanstack/react-query' import {useComposerControls} from '#/state/shell/composer' import {listenSoftReset} from '#/state/events' -import {truncateAndInvalidate} from '#/state/queries/util' -import {Text} from '#/view/com/util/text/Text' -import {usePalette} from 'lib/hooks/usePalette' -import {isNative} from '#/platform/detection' import {isInvalidHandle} from '#/lib/strings/handles' +import {ProfileFeedSection} from '#/screens/Profile/Sections/Feed' +import {ProfileLabelsSection} from '#/screens/Profile/Sections/Labels' +import {ProfileHeader, ProfileHeaderLoading} from '#/screens/Profile/Header' + interface SectionRef { scrollToTop: () => void } @@ -148,16 +139,24 @@ function ProfileScreenLoaded({ const setMinimalShellMode = useSetMinimalShellMode() const {openComposer} = useComposerControls() const {screen, track} = useAnalytics() + const { + data: labelerInfo, + error: labelerError, + isLoading: isLabelerLoading, + } = useLabelerInfoQuery({ + did: profile.did, + enabled: !!profile.associated?.labeler, + }) const [currentPage, setCurrentPage] = React.useState(0) const {_} = useLingui() const setDrawerSwipeDisabled = useSetDrawerSwipeDisabled() - const extraInfoQuery = useProfileExtraInfoQuery(profile.did) const postsSectionRef = React.useRef<SectionRef>(null) const repliesSectionRef = React.useRef<SectionRef>(null) const mediaSectionRef = React.useRef<SectionRef>(null) const likesSectionRef = React.useRef<SectionRef>(null) const feedsSectionRef = React.useRef<SectionRef>(null) const listsSectionRef = React.useRef<SectionRef>(null) + const labelsSectionRef = React.useRef<SectionRef>(null) useSetTitle(combinedDisplayName(profile)) @@ -171,44 +170,75 @@ function ProfileScreenLoaded({ ) const isMe = profile.did === currentAccount?.did + const hasLabeler = !!profile.associated?.labeler + const showFiltersTab = hasLabeler + const showPostsTab = true const showRepliesTab = hasSession + const showMediaTab = !hasLabeler const showLikesTab = isMe - const showFeedsTab = hasSession && (isMe || extraInfoQuery.data?.hasFeedgens) - const showListsTab = hasSession && (isMe || extraInfoQuery.data?.hasLists) + const showFeedsTab = + hasSession && (isMe || (profile.associated?.feedgens || 0) > 0) + const showListsTab = + hasSession && (isMe || (profile.associated?.lists || 0) > 0) + const sectionTitles = useMemo<string[]>(() => { return [ - _(msg`Posts`), + showFiltersTab ? _(msg`Labels`) : undefined, + showListsTab && hasLabeler ? _(msg`Lists`) : undefined, + showPostsTab ? _(msg`Posts`) : undefined, showRepliesTab ? _(msg`Replies`) : undefined, - _(msg`Media`), + showMediaTab ? _(msg`Media`) : undefined, showLikesTab ? _(msg`Likes`) : undefined, showFeedsTab ? _(msg`Feeds`) : undefined, - showListsTab ? _(msg`Lists`) : undefined, + showListsTab && !hasLabeler ? _(msg`Lists`) : undefined, ].filter(Boolean) as string[] - }, [showRepliesTab, showLikesTab, showFeedsTab, showListsTab, _]) + }, [ + showPostsTab, + showRepliesTab, + showMediaTab, + showLikesTab, + showFeedsTab, + showListsTab, + showFiltersTab, + hasLabeler, + _, + ]) let nextIndex = 0 - const postsIndex = nextIndex++ + let filtersIndex: number | null = null + let postsIndex: number | null = null let repliesIndex: number | null = null + let mediaIndex: number | null = null + let likesIndex: number | null = null + let feedsIndex: number | null = null + let listsIndex: number | null = null + if (showFiltersTab) { + filtersIndex = nextIndex++ + } + if (showPostsTab) { + postsIndex = nextIndex++ + } if (showRepliesTab) { repliesIndex = nextIndex++ } - const mediaIndex = nextIndex++ - let likesIndex: number | null = null + if (showMediaTab) { + mediaIndex = nextIndex++ + } if (showLikesTab) { likesIndex = nextIndex++ } - let feedsIndex: number | null = null if (showFeedsTab) { feedsIndex = nextIndex++ } - let listsIndex: number | null = null if (showListsTab) { listsIndex = nextIndex++ } const scrollSectionToTop = React.useCallback( (index: number) => { - if (index === postsIndex) { + if (index === filtersIndex) { + labelsSectionRef.current?.scrollToTop() + } else if (index === postsIndex) { postsSectionRef.current?.scrollToTop() } else if (index === repliesIndex) { repliesSectionRef.current?.scrollToTop() @@ -222,7 +252,15 @@ function ProfileScreenLoaded({ listsSectionRef.current?.scrollToTop() } }, - [postsIndex, repliesIndex, mediaIndex, likesIndex, feedsIndex, listsIndex], + [ + filtersIndex, + postsIndex, + repliesIndex, + mediaIndex, + likesIndex, + feedsIndex, + listsIndex, + ], ) useFocusEffect( @@ -278,6 +316,7 @@ function ProfileScreenLoaded({ return ( <ProfileHeader profile={profile} + labeler={labelerInfo} descriptionRT={hasDescription ? descriptionRT : null} moderationOpts={moderationOpts} hideBackButton={hideBackButton} @@ -286,6 +325,7 @@ function ProfileScreenLoaded({ ) }, [ profile, + labelerInfo, descriptionRT, hasDescription, moderationOpts, @@ -297,8 +337,8 @@ function ProfileScreenLoaded({ <ScreenHider testID="profileView" style={styles.container} - screenDescription="profile" - moderation={moderation.account}> + screenDescription={_(msg`profile`)} + modui={moderation.ui('profileView')}> <PagerWithHeader testID="profilePager" isHeaderReady={!showPlaceholder} @@ -306,19 +346,45 @@ function ProfileScreenLoaded({ onPageSelected={onPageSelected} onCurrentPageSelected={onCurrentPageSelected} renderHeader={renderHeader}> - {({headerHeight, isFocused, scrollElRef}) => ( - <FeedSection - ref={postsSectionRef} - feed={`author|${profile.did}|posts_and_author_threads`} - headerHeight={headerHeight} - isFocused={isFocused} - scrollElRef={scrollElRef as ListRef} - ignoreFilterFor={profile.did} - /> - )} + {showFiltersTab + ? ({headerHeight, scrollElRef}) => ( + <ProfileLabelsSection + ref={labelsSectionRef} + labelerInfo={labelerInfo} + labelerError={labelerError} + isLabelerLoading={isLabelerLoading} + moderationOpts={moderationOpts} + scrollElRef={scrollElRef as ListRef} + headerHeight={headerHeight} + /> + ) + : null} + {showListsTab && !!profile.associated?.labeler + ? ({headerHeight, isFocused, scrollElRef}) => ( + <ProfileLists + ref={listsSectionRef} + did={profile.did} + scrollElRef={scrollElRef as ListRef} + headerOffset={headerHeight} + enabled={isFocused} + /> + ) + : null} + {showPostsTab + ? ({headerHeight, isFocused, scrollElRef}) => ( + <ProfileFeedSection + ref={postsSectionRef} + feed={`author|${profile.did}|posts_and_author_threads`} + headerHeight={headerHeight} + isFocused={isFocused} + scrollElRef={scrollElRef as ListRef} + ignoreFilterFor={profile.did} + /> + ) + : null} {showRepliesTab ? ({headerHeight, isFocused, scrollElRef}) => ( - <FeedSection + <ProfileFeedSection ref={repliesSectionRef} feed={`author|${profile.did}|posts_with_replies`} headerHeight={headerHeight} @@ -328,19 +394,21 @@ function ProfileScreenLoaded({ /> ) : null} - {({headerHeight, isFocused, scrollElRef}) => ( - <FeedSection - ref={mediaSectionRef} - feed={`author|${profile.did}|posts_with_media`} - headerHeight={headerHeight} - isFocused={isFocused} - scrollElRef={scrollElRef as ListRef} - ignoreFilterFor={profile.did} - /> - )} + {showMediaTab + ? ({headerHeight, isFocused, scrollElRef}) => ( + <ProfileFeedSection + ref={mediaSectionRef} + feed={`author|${profile.did}|posts_with_media`} + headerHeight={headerHeight} + isFocused={isFocused} + scrollElRef={scrollElRef as ListRef} + ignoreFilterFor={profile.did} + /> + ) + : null} {showLikesTab ? ({headerHeight, isFocused, scrollElRef}) => ( - <FeedSection + <ProfileFeedSection ref={likesSectionRef} feed={`likes|${profile.did}`} headerHeight={headerHeight} @@ -361,7 +429,7 @@ function ProfileScreenLoaded({ /> ) : null} - {showListsTab + {showListsTab && !profile.associated?.labeler ? ({headerHeight, isFocused, scrollElRef}) => ( <ProfileLists ref={listsSectionRef} @@ -387,77 +455,6 @@ function ProfileScreenLoaded({ ) } -interface FeedSectionProps { - feed: FeedDescriptor - headerHeight: number - isFocused: boolean - scrollElRef: ListRef - ignoreFilterFor?: string -} -const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>( - function FeedSectionImpl( - {feed, headerHeight, isFocused, scrollElRef, ignoreFilterFor}, - ref, - ) { - const {_} = useLingui() - const queryClient = useQueryClient() - const [hasNew, setHasNew] = React.useState(false) - const [isScrolledDown, setIsScrolledDown] = React.useState(false) - - const onScrollToTop = React.useCallback(() => { - scrollElRef.current?.scrollToOffset({ - animated: isNative, - offset: -headerHeight, - }) - truncateAndInvalidate(queryClient, FEED_RQKEY(feed)) - setHasNew(false) - }, [scrollElRef, headerHeight, queryClient, feed, setHasNew]) - React.useImperativeHandle(ref, () => ({ - scrollToTop: onScrollToTop, - })) - - const renderPostsEmpty = React.useCallback(() => { - return <EmptyState icon="feed" message={_(msg`This feed is empty!`)} /> - }, [_]) - - return ( - <View> - <Feed - testID="postsFeed" - enabled={isFocused} - feed={feed} - scrollElRef={scrollElRef} - onHasNew={setHasNew} - onScrolledDownChange={setIsScrolledDown} - renderEmptyState={renderPostsEmpty} - headerOffset={headerHeight} - renderEndOfFeed={ProfileEndOfFeed} - ignoreFilterFor={ignoreFilterFor} - /> - {(isScrolledDown || hasNew) && ( - <LoadLatestBtn - onPress={onScrollToTop} - label={_(msg`Load new posts`)} - showIndicator={hasNew} - /> - )} - </View> - ) - }, -) - -function ProfileEndOfFeed() { - const pal = usePalette('default') - - return ( - <View style={[pal.border, {paddingTop: 32, borderTopWidth: 1}]}> - <Text style={[pal.textLight, pal.border, {textAlign: 'center'}]}> - <Trans>End of feed</Trans> - </Text> - </View> - ) -} - function useRichText(text: string): [RichTextAPI, boolean] { const [prevText, setPrevText] = React.useState(text) const [rawRT, setRawRT] = React.useState(() => new RichTextAPI({text})) diff --git a/src/view/screens/ProfileFeed.tsx b/src/view/screens/ProfileFeed.tsx index 212c10e74..8eeeb5d90 100644 --- a/src/view/screens/ProfileFeed.tsx +++ b/src/view/screens/ProfileFeed.tsx @@ -1,11 +1,9 @@ import React, {useMemo, useCallback} from 'react' -import {Dimensions, StyleSheet, View} from 'react-native' +import {StyleSheet, View, Pressable} from 'react-native' import {NativeStackScreenProps} from '@react-navigation/native-stack' import {useIsFocused, useNavigation} from '@react-navigation/native' import {useQueryClient} from '@tanstack/react-query' import {usePalette} from 'lib/hooks/usePalette' -import {HeartIcon, HeartIconSolid} from 'lib/icons' -import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {CommonNavigatorParams} from 'lib/routes/types' import {makeRecordUri} from 'lib/strings/url-helpers' import {s} from 'lib/styles' @@ -13,7 +11,7 @@ import {FeedDescriptor} from '#/state/queries/post-feed' import {PagerWithHeader} from 'view/com/pager/PagerWithHeader' import {ProfileSubpageHeader} from 'view/com/profile/ProfileSubpageHeader' import {Feed} from 'view/com/posts/Feed' -import {TextLink} from 'view/com/util/Link' +import {InlineLink} from '#/components/Link' import {ListRef} from 'view/com/util/List' import {Button} from 'view/com/util/forms/Button' import {Text} from 'view/com/util/text/Text' @@ -29,20 +27,15 @@ import {shareUrl} from 'lib/sharing' import {toShareUrl} from 'lib/strings/url-helpers' import {Haptics} from 'lib/haptics' import {useAnalytics} from 'lib/analytics/analytics' -import {NativeDropdown, DropdownItem} from 'view/com/util/forms/NativeDropdown' -import {useScrollHandlers} from '#/lib/ScrollContext' -import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED' import {makeCustomFeedLink} from 'lib/routes/links' import {pluralize} from 'lib/strings/helpers' -import {CenteredView, ScrollView} from 'view/com/util/Views' +import {CenteredView} from 'view/com/util/Views' import {NavigationProp} from 'lib/routes/types' -import {sanitizeHandle} from 'lib/strings/handles' -import {makeProfileLink} from 'lib/routes/links' import {ComposeIcon2} from 'lib/icons' import {logger} from '#/logger' import {Trans, msg} from '@lingui/macro' import {useLingui} from '@lingui/react' -import {useModalControls} from '#/state/modals' +import {ReportDialog, useReportDialogControl} from '#/components/ReportDialog' import {useFeedSourceInfoQuery, FeedSourceFeedInfo} from '#/state/queries/feed' import {useResolveUriQuery} from '#/state/queries/resolve-uri' import { @@ -59,9 +52,21 @@ import {useComposerControls} from '#/state/shell/composer' import {truncateAndInvalidate} from '#/state/queries/util' import {isNative} from '#/platform/detection' import {listenSoftReset} from '#/state/events' -import {atoms as a} from '#/alf' +import {atoms as a, useTheme} from '#/alf' +import * as Menu from '#/components/Menu' +import {HITSLOP_20} from '#/lib/constants' +import {DotGrid_Stroke2_Corner0_Rounded as Ellipsis} from '#/components/icons/DotGrid' +import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash' +import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus' +import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfo} from '#/components/icons/CircleInfo' +import {ArrowOutOfBox_Stroke2_Corner0_Rounded as Share} from '#/components/icons/ArrowOutOfBox' +import { + Heart2_Stroke2_Corner0_Rounded as HeartOutline, + Heart2_Filled_Stroke2_Corner0_Rounded as HeartFilled, +} from '#/components/icons/Heart2' +import {Button as NewButton, ButtonText} from '#/components/Button' -const SECTION_TITLES = ['Posts', 'About'] +const SECTION_TITLES = ['Posts'] interface SectionRef { scrollToTop: () => void @@ -103,8 +108,8 @@ export function ProfileFeedScreen(props: Props) { <View style={{flexDirection: 'row'}}> <Button type="default" - accessibilityLabel={_(msg`Go Back`)} - accessibilityHint="Return to previous page" + accessibilityLabel={_(msg`Go back`)} + accessibilityHint={_(msg`Returns to previous page`)} onPress={onPressBack} style={{flexShrink: 1}}> <Text type="button" style={pal.text}> @@ -148,9 +153,9 @@ export function ProfileFeedScreenInner({ feedInfo: FeedSourceFeedInfo }) { const {_} = useLingui() - const pal = usePalette('default') + const t = useTheme() const {hasSession, currentAccount} = useSession() - const {openModal} = useModalControls() + const reportDialogControl = useReportDialogControl() const {openComposer} = useComposerControls() const {track} = useAnalytics() const feedSectionRef = React.useRef<SectionRef>(null) @@ -200,9 +205,11 @@ export function ProfileFeedScreenInner({ if (isSaved) { await removeFeed({uri: feedInfo.uri}) resetRemoveFeed() + Toast.show(_(msg`Removed from your feeds`)) } else { await saveFeed({uri: feedInfo.uri}) resetSaveFeed() + Toast.show(_(msg`Saved to your feeds`)) } } catch (err) { Toast.show( @@ -246,13 +253,8 @@ export function ProfileFeedScreenInner({ }, [feedInfo, track]) const onPressReport = React.useCallback(() => { - if (!feedInfo) return - openModal({ - name: 'report', - uri: feedInfo.uri, - cid: feedInfo.cid, - }) - }, [openModal, feedInfo]) + reportDialogControl.open() + }, [reportDialogControl]) const onCurrentPageSelected = React.useCallback( (index: number) => { @@ -263,134 +265,144 @@ export function ProfileFeedScreenInner({ [feedSectionRef], ) - // render - // = - - const dropdownItems: DropdownItem[] = React.useMemo(() => { - return [ - hasSession && { - testID: 'feedHeaderDropdownToggleSavedBtn', - label: isSaved ? _(msg`Remove from my feeds`) : _(msg`Add to my feeds`), - onPress: isSavePending || isRemovePending ? undefined : onToggleSaved, - icon: isSaved - ? { - ios: { - name: 'trash', - }, - android: 'ic_delete', - web: ['far', 'trash-can'], - } - : { - ios: { - name: 'plus', - }, - android: '', - web: 'plus', - }, - }, - hasSession && { - testID: 'feedHeaderDropdownReportBtn', - label: _(msg`Report feed`), - onPress: onPressReport, - icon: { - ios: { - name: 'exclamationmark.triangle', - }, - android: 'ic_menu_report_image', - web: 'circle-exclamation', - }, - }, - { - testID: 'feedHeaderDropdownShareBtn', - label: _(msg`Share feed`), - onPress: onPressShare, - icon: { - ios: { - name: 'square.and.arrow.up', - }, - android: 'ic_menu_share', - web: 'share', - }, - }, - ].filter(Boolean) as DropdownItem[] - }, [ - hasSession, - onToggleSaved, - onPressReport, - onPressShare, - isSaved, - isSavePending, - isRemovePending, - _, - ]) - const renderHeader = useCallback(() => { return ( - <ProfileSubpageHeader - isLoading={false} - href={feedInfo.route.href} - title={feedInfo?.displayName} - avatar={feedInfo?.avatar} - isOwner={feedInfo.creatorDid === currentAccount?.did} - creator={ - feedInfo - ? {did: feedInfo.creatorDid, handle: feedInfo.creatorHandle} - : undefined - } - avatarType="algo"> - {feedInfo && hasSession && ( - <> - <Button - disabled={isSavePending || isRemovePending} - type="default" - label={isSaved ? _(msg`Unsave`) : _(msg`Save`)} - onPress={onToggleSaved} - style={styles.btn} - /> - <Button - testID={isPinned ? 'unpinBtn' : 'pinBtn'} - disabled={isPinPending || isUnpinPending} - type={isPinned ? 'default' : 'inverted'} - label={isPinned ? _(msg`Unpin`) : _(msg`Pin to home`)} - onPress={onTogglePinned} - style={styles.btn} - /> - </> - )} - <NativeDropdown - testID="headerDropdownBtn" - items={dropdownItems} - accessibilityLabel={_(msg`More options`)} - accessibilityHint=""> - <View style={[pal.viewLight, styles.btn]}> - <FontAwesomeIcon - icon="ellipsis" - size={20} - color={pal.colors.text} - /> + <> + <ProfileSubpageHeader + isLoading={false} + href={feedInfo.route.href} + title={feedInfo?.displayName} + avatar={feedInfo?.avatar} + isOwner={feedInfo.creatorDid === currentAccount?.did} + creator={ + feedInfo + ? {did: feedInfo.creatorDid, handle: feedInfo.creatorHandle} + : undefined + } + avatarType="algo"> + <View style={[a.flex_row, a.align_center, a.gap_sm]}> + {feedInfo && hasSession && ( + <NewButton + testID={isPinned ? 'unpinBtn' : 'pinBtn'} + disabled={isPinPending || isUnpinPending} + size="small" + variant="solid" + color={isPinned ? 'secondary' : 'primary'} + label={isPinned ? _(msg`Unpin from home`) : _(msg`Pin to home`)} + onPress={onTogglePinned}> + <ButtonText> + {isPinned ? _(msg`Unpin`) : _(msg`Pin to Home`)} + </ButtonText> + </NewButton> + )} + <Menu.Root> + <Menu.Trigger label={_(msg`Open feed options menu`)}> + {({props, state}) => { + return ( + <Pressable + {...props} + hitSlop={HITSLOP_20} + style={[ + a.justify_center, + a.align_center, + a.rounded_full, + {height: 36, width: 36}, + t.atoms.bg_contrast_50, + (state.hovered || state.pressed) && [ + t.atoms.bg_contrast_100, + ], + ]} + testID="headerDropdownBtn"> + <Ellipsis + size="lg" + fill={t.atoms.text_contrast_medium.color} + /> + </Pressable> + ) + }} + </Menu.Trigger> + + <Menu.Outer> + <Menu.Group> + {hasSession && ( + <> + <Menu.Item + disabled={isSavePending || isRemovePending} + testID="feedHeaderDropdownToggleSavedBtn" + label={ + isSaved + ? _(msg`Remove from my feeds`) + : _(msg`Save to my feeds`) + } + onPress={onToggleSaved}> + <Menu.ItemText> + {isSaved + ? _(msg`Remove from my feeds`) + : _(msg`Save to my feeds`)} + </Menu.ItemText> + <Menu.ItemIcon + icon={isSaved ? Trash : Plus} + position="right" + /> + </Menu.Item> + + <Menu.Item + testID="feedHeaderDropdownReportBtn" + label={_(msg`Report feed`)} + onPress={onPressReport}> + <Menu.ItemText>{_(msg`Report feed`)}</Menu.ItemText> + <Menu.ItemIcon icon={CircleInfo} position="right" /> + </Menu.Item> + </> + )} + + <Menu.Item + testID="feedHeaderDropdownShareBtn" + label={_(msg`Share feed`)} + onPress={onPressShare}> + <Menu.ItemText>{_(msg`Share feed`)}</Menu.ItemText> + <Menu.ItemIcon icon={Share} position="right" /> + </Menu.Item> + </Menu.Group> + </Menu.Outer> + </Menu.Root> </View> - </NativeDropdown> - </ProfileSubpageHeader> + </ProfileSubpageHeader> + <AboutSection + feedOwnerDid={feedInfo.creatorDid} + feedRkey={feedInfo.route.params.rkey} + feedInfo={feedInfo} + /> + </> ) }, [ _, hasSession, - pal, feedInfo, isPinned, onTogglePinned, onToggleSaved, - dropdownItems, currentAccount?.did, isPinPending, isRemovePending, isSavePending, isSaved, isUnpinPending, + onPressReport, + onPressShare, + t, ]) return ( <View style={s.hContentRegion}> + <ReportDialog + control={reportDialogControl} + params={{ + type: 'feedgen', + uri: feedInfo.uri, + cid: feedInfo.cid, + }} + /> <PagerWithHeader items={SECTION_TITLES} isHeaderReady={true} @@ -405,18 +417,6 @@ export function ProfileFeedScreenInner({ isFocused={isScreenFocused && isFocused} /> )} - {({headerHeight, scrollElRef}) => ( - <AboutSection - feedOwnerDid={feedInfo.creatorDid} - feedRkey={feedInfo.route.params.rkey} - feedInfo={feedInfo} - headerHeight={headerHeight} - scrollElRef={ - scrollElRef as React.MutableRefObject<ScrollView | null> - } - isOwner={feedInfo.creatorDid === currentAccount?.did} - /> - )} </PagerWithHeader> {hasSession && ( <FAB @@ -505,21 +505,14 @@ function AboutSection({ feedOwnerDid, feedRkey, feedInfo, - headerHeight, - scrollElRef, - isOwner, }: { feedOwnerDid: string feedRkey: string feedInfo: FeedSourceFeedInfo - headerHeight: number - scrollElRef: React.MutableRefObject<ScrollView | null> - isOwner: boolean }) { + const t = useTheme() const pal = usePalette('default') const {_} = useLingui() - const scrollHandlers = useScrollHandlers() - const onScroll = useAnimatedScrollHandler(scrollHandlers) const [likeUri, setLikeUri] = React.useState(feedInfo.likeUri) const {hasSession} = useSession() const {track} = useAnalytics() @@ -555,24 +548,8 @@ function AboutSection({ }, [likeUri, isLiked, feedInfo, likeFeed, unlikeFeed, track, _]) return ( - <ScrollView - ref={scrollElRef} - onScroll={onScroll} - scrollEventThrottle={1} - contentContainerStyle={{ - paddingTop: headerHeight, - minHeight: Dimensions.get('window').height * 1.5, - }}> - <View - style={[ - { - borderTopWidth: 1, - paddingVertical: 20, - paddingHorizontal: 20, - gap: 12, - }, - pal.border, - ]}> + <View style={[styles.aboutSectionContainer]}> + <View style={[a.pt_sm]}> {feedInfo.description ? ( <RichText testID="listDescription" @@ -584,50 +561,34 @@ function AboutSection({ <Trans>No description</Trans> </Text> )} - <View style={{flexDirection: 'row', alignItems: 'center', gap: 10}}> - <Button - type="default" - testID="toggleLikeBtn" - accessibilityLabel={_(msg`Like this feed`)} - accessibilityHint="" - disabled={!hasSession || isLikePending || isUnlikePending} - onPress={onToggleLiked} - style={{paddingHorizontal: 10}}> - {isLiked ? ( - <HeartIconSolid size={19} style={s.likeColor} /> - ) : ( - <HeartIcon strokeWidth={3} size={19} style={pal.textLight} /> - )} - </Button> - {typeof likeCount === 'number' && ( - <TextLink - href={makeCustomFeedLink(feedOwnerDid, feedRkey, 'liked-by')} - text={_( - msg`Liked by ${likeCount} ${pluralize(likeCount, 'user')}`, - )} - style={[pal.textLight, s.semiBold]} - /> - )} - </View> - <Text type="md" style={[pal.textLight]} numberOfLines={1}> - {isOwner ? ( - <Trans>Created by you</Trans> + </View> + + <View style={[a.flex_row, a.gap_sm, a.align_center, a.pb_sm]}> + <NewButton + size="small" + variant="solid" + color="secondary" + shape="round" + label={isLiked ? _(msg`Unlike this feed`) : _(msg`Like this feed`)} + testID="toggleLikeBtn" + disabled={!hasSession || isLikePending || isUnlikePending} + onPress={onToggleLiked}> + {isLiked ? ( + <HeartFilled size="md" fill={s.likeColor.color} /> ) : ( - <Trans> - Created by{' '} - <TextLink - text={sanitizeHandle(feedInfo.creatorHandle, '@')} - href={makeProfileLink({ - did: feedInfo.creatorDid, - handle: feedInfo.creatorHandle, - })} - style={pal.textLight} - /> - </Trans> + <HeartOutline size="md" fill={t.atoms.text_contrast_medium.color} /> )} - </Text> + </NewButton> + {typeof likeCount === 'number' && ( + <InlineLink + label={_(msg`View users who like this feed`)} + to={makeCustomFeedLink(feedOwnerDid, feedRkey, 'liked-by')} + style={[t.atoms.text_contrast_medium, a.font_bold]}> + {_(msg`Liked by ${likeCount} ${pluralize(likeCount, 'user')}`)} + </InlineLink> + )} </View> - </ScrollView> + </View> ) } @@ -647,4 +608,9 @@ const styles = StyleSheet.create({ paddingVertical: 14, borderRadius: 6, }, + aboutSectionContainer: { + paddingVertical: 4, + paddingHorizontal: 16, + gap: 12, + }, }) diff --git a/src/view/screens/ProfileFollowers.tsx b/src/view/screens/ProfileFollowers.tsx index 2cad08cb5..6f8ecc2e8 100644 --- a/src/view/screens/ProfileFollowers.tsx +++ b/src/view/screens/ProfileFollowers.tsx @@ -21,7 +21,7 @@ export const ProfileFollowersScreen = ({route}: Props) => { ) return ( - <View> + <View style={{flex: 1}}> <ViewHeader title={_(msg`Followers`)} /> <ProfileFollowersComponent name={name} /> </View> diff --git a/src/view/screens/ProfileFollows.tsx b/src/view/screens/ProfileFollows.tsx index 80502b98b..bdab20153 100644 --- a/src/view/screens/ProfileFollows.tsx +++ b/src/view/screens/ProfileFollows.tsx @@ -21,7 +21,7 @@ export const ProfileFollowsScreen = ({route}: Props) => { ) return ( - <View> + <View style={{flex: 1}}> <ViewHeader title={_(msg`Following`)} /> <ProfileFollowsComponent name={name} /> </View> diff --git a/src/view/screens/ProfileList.tsx b/src/view/screens/ProfileList.tsx index 9e98757ef..58b89f239 100644 --- a/src/view/screens/ProfileList.tsx +++ b/src/view/screens/ProfileList.tsx @@ -39,6 +39,7 @@ import {Trans, msg} from '@lingui/macro' import {useLingui} from '@lingui/react' import {useSetMinimalShellMode} from '#/state/shell' import {useModalControls} from '#/state/modals' +import {ReportDialog, useReportDialogControl} from '#/components/ReportDialog' import {useResolveUriQuery} from '#/state/queries/resolve-uri' import { useListQuery, @@ -61,6 +62,8 @@ import {logger} from '#/logger' import {useAnalytics} from '#/lib/analytics/analytics' import {listenSoftReset} from '#/state/events' import {atoms as a, useTheme} from '#/alf' +import * as Prompt from '#/components/Prompt' +import {useDialogControl} from '#/components/Dialog' const SECTION_TITLES_CURATE = ['Posts', 'About'] const SECTION_TITLES_MOD = ['About'] @@ -234,7 +237,8 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) { const {_} = useLingui() const navigation = useNavigation<NavigationProp>() const {currentAccount} = useSession() - const {openModal, closeModal} = useModalControls() + const reportDialogControl = useReportDialogControl() + const {openModal} = useModalControls() const listMuteMutation = useListMuteMutation() const listBlockMutation = useListBlockMutation() const listDeleteMutation = useListDeleteMutation() @@ -251,6 +255,10 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) { const {mutate: setSavedFeeds} = useSetSaveFeedsMutation() const {track} = useAnalytics() + const deleteListPromptControl = useDialogControl() + const subscribeMutePromptControl = useDialogControl() + const subscribeBlockPromptControl = useDialogControl() + const isPinned = preferences?.feeds?.pinned?.includes(list.uri) const isSaved = preferences?.feeds?.saved?.includes(list.uri) @@ -269,32 +277,19 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) { } }, [list.uri, isPinned, pinFeed, unpinFeed, _]) - const onSubscribeMute = useCallback(() => { - openModal({ - name: 'confirm', - title: _(msg`Mute these accounts?`), - message: _( - msg`Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them.`, - ), - confirmBtnText: _(msg`Mute this List`), - async onPressConfirm() { - try { - await listMuteMutation.mutateAsync({uri: list.uri, mute: true}) - Toast.show(_(msg`List muted`)) - track('Lists:Mute') - } catch { - Toast.show( - _( - msg`There was an issue. Please check your internet connection and try again.`, - ), - ) - } - }, - onPressCancel() { - closeModal() - }, - }) - }, [openModal, closeModal, list, listMuteMutation, track, _]) + const onSubscribeMute = useCallback(async () => { + try { + await listMuteMutation.mutateAsync({uri: list.uri, mute: true}) + Toast.show(_(msg`List muted`)) + track('Lists:Mute') + } catch { + Toast.show( + _( + msg`There was an issue. Please check your internet connection and try again.`, + ), + ) + } + }, [list, listMuteMutation, track, _]) const onUnsubscribeMute = useCallback(async () => { try { @@ -310,32 +305,19 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) { } }, [list, listMuteMutation, track, _]) - const onSubscribeBlock = useCallback(() => { - openModal({ - name: 'confirm', - title: _(msg`Block these accounts?`), - message: _( - msg`Blocking is public. Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you.`, - ), - confirmBtnText: _(msg`Block this List`), - async onPressConfirm() { - try { - await listBlockMutation.mutateAsync({uri: list.uri, block: true}) - Toast.show(_(msg`List blocked`)) - track('Lists:Block') - } catch { - Toast.show( - _( - msg`There was an issue. Please check your internet connection and try again.`, - ), - ) - } - }, - onPressCancel() { - closeModal() - }, - }) - }, [openModal, closeModal, list, listBlockMutation, track, _]) + const onSubscribeBlock = useCallback(async () => { + try { + await listBlockMutation.mutateAsync({uri: list.uri, block: true}) + Toast.show(_(msg`List blocked`)) + track('Lists:Block') + } catch { + Toast.show( + _( + msg`There was an issue. Please check your internet connection and try again.`, + ), + ) + } + }, [list, listBlockMutation, track, _]) const onUnsubscribeBlock = useCallback(async () => { try { @@ -358,34 +340,26 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) { }) }, [openModal, list]) - const onPressDelete = useCallback(() => { - openModal({ - name: 'confirm', - title: _(msg`Delete List`), - message: _(msg`Are you sure?`), - async onPressConfirm() { - await listDeleteMutation.mutateAsync({uri: list.uri}) - - if (isSaved || isPinned) { - const {saved, pinned} = preferences!.feeds - - setSavedFeeds({ - saved: isSaved ? saved.filter(uri => uri !== list.uri) : saved, - pinned: isPinned ? pinned.filter(uri => uri !== list.uri) : pinned, - }) - } + const onPressDelete = useCallback(async () => { + await listDeleteMutation.mutateAsync({uri: list.uri}) - Toast.show(_(msg`List deleted`)) - track('Lists:Delete') - if (navigation.canGoBack()) { - navigation.goBack() - } else { - navigation.navigate('Home') - } - }, - }) + if (isSaved || isPinned) { + const {saved, pinned} = preferences!.feeds + + setSavedFeeds({ + saved: isSaved ? saved.filter(uri => uri !== list.uri) : saved, + pinned: isPinned ? pinned.filter(uri => uri !== list.uri) : pinned, + }) + } + + Toast.show(_(msg`List deleted`)) + track('Lists:Delete') + if (navigation.canGoBack()) { + navigation.goBack() + } else { + navigation.navigate('Home') + } }, [ - openModal, list, listDeleteMutation, navigation, @@ -398,12 +372,8 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) { ]) const onPressReport = useCallback(() => { - openModal({ - name: 'report', - uri: list.uri, - cid: list.cid, - }) - }, [openModal, list]) + reportDialogControl.open() + }, [reportDialogControl]) const onPressShare = useCallback(() => { const url = toShareUrl(`/profile/${list.creator.did}/lists/${rkey}`) @@ -443,7 +413,7 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) { items.push({ testID: 'listHeaderDropdownDeleteBtn', label: _(msg`Delete List`), - onPress: onPressDelete, + onPress: deleteListPromptControl.open, icon: { ios: { name: 'trash', @@ -489,7 +459,9 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) { items.push({ testID: 'listHeaderDropdownMuteBtn', label: isMuting ? _(msg`Un-mute list`) : _(msg`Mute list`), - onPress: isMuting ? onUnsubscribeMute : onSubscribeMute, + onPress: isMuting + ? onUnsubscribeMute + : subscribeMutePromptControl.open, icon: { ios: { name: isMuting ? 'eye' : 'eye.slash', @@ -504,7 +476,9 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) { items.push({ testID: 'listHeaderDropdownBlockBtn', label: isBlocking ? _(msg`Un-block list`) : _(msg`Block list`), - onPress: isBlocking ? onUnsubscribeBlock : onSubscribeBlock, + onPress: isBlocking + ? onUnsubscribeBlock + : subscribeBlockPromptControl.open, icon: { ios: { name: 'person.fill.xmark', @@ -517,24 +491,24 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) { } return items }, [ - isOwner, - onPressShare, - onPressEdit, - onPressDelete, - onPressReport, _, + onPressShare, + isOwner, isModList, isPinned, - unpinFeed, + isCurateList, + onPressEdit, + deleteListPromptControl.open, + onPressReport, isPending, + unpinFeed, list.uri, - isCurateList, - isMuting, isBlocking, + isMuting, onUnsubscribeMute, - onSubscribeMute, + subscribeMutePromptControl.open, onUnsubscribeBlock, - onSubscribeBlock, + subscribeBlockPromptControl.open, ]) const subscribeDropdownItems: DropdownItem[] = useMemo(() => { @@ -542,7 +516,7 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) { { testID: 'subscribeDropdownMuteBtn', label: _(msg`Mute accounts`), - onPress: onSubscribeMute, + onPress: subscribeMutePromptControl.open, icon: { ios: { name: 'speaker.slash', @@ -554,7 +528,7 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) { { testID: 'subscribeDropdownBlockBtn', label: _(msg`Block accounts`), - onPress: onSubscribeBlock, + onPress: subscribeBlockPromptControl.open, icon: { ios: { name: 'person.fill.xmark', @@ -564,7 +538,7 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) { }, }, ] - }, [onSubscribeMute, onSubscribeBlock, _]) + }, [_, subscribeMutePromptControl.open, subscribeBlockPromptControl.open]) return ( <ProfileSubpageHeader @@ -574,6 +548,14 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) { isOwner={list.creator.did === currentAccount?.did} creator={list.creator} avatarType="list"> + <ReportDialog + control={reportDialogControl} + params={{ + type: 'list', + uri: list.uri, + cid: list.cid, + }} + /> {isCurateList || isPinned ? ( <Button testID={isPinned ? 'unpinBtn' : 'pinBtn'} @@ -620,6 +602,38 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) { <FontAwesomeIcon icon="ellipsis" size={20} color={pal.colors.text} /> </View> </NativeDropdown> + + <Prompt.Basic + control={deleteListPromptControl} + title={_(msg`Delete this list?`)} + description={_( + msg`If you delete this list, you won't be able to recover it.`, + )} + onConfirm={onPressDelete} + confirmButtonCta={_(msg`Delete`)} + confirmButtonColor="negative" + /> + + <Prompt.Basic + control={subscribeMutePromptControl} + title={_(msg`Mute these accounts?`)} + description={_( + msg`Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them.`, + )} + onConfirm={onSubscribeMute} + confirmButtonCta={_(msg`Mute list`)} + /> + + <Prompt.Basic + control={subscribeBlockPromptControl} + title={_(msg`Block these accounts?`)} + description={_( + msg`Blocking is public. Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you.`, + )} + onConfirm={onSubscribeBlock} + confirmButtonCta={_(msg`Block list`)} + confirmButtonColor="negative" + /> </ProfileSubpageHeader> ) } @@ -899,7 +913,7 @@ function ErrorScreen({error}: {error: string}) { <View style={{flexDirection: 'row'}}> <Button type="default" - accessibilityLabel={_(msg`Go Back`)} + accessibilityLabel={_(msg`Go back`)} accessibilityHint={_(msg`Return to previous page`)} onPress={onPressBack} style={{flexShrink: 1}}> diff --git a/src/view/screens/Search/Search.tsx b/src/view/screens/Search/Search.tsx index 42eec53d3..d39f37ed7 100644 --- a/src/view/screens/Search/Search.tsx +++ b/src/view/screens/Search/Search.tsx @@ -141,6 +141,7 @@ function SearchScreenSuggestedFollows() { friends.slice(0, 4).map(friend => getSuggestedFollowsByActor(friend.did).then(foafsRes => { for (const user of foafsRes.suggestions) { + if (user.associated?.labeler) continue friendsOfFriends.set(user.did, user) } }), @@ -772,7 +773,7 @@ export function SearchScreen( {searchHistory.length > 0 && ( <View style={styles.searchHistoryContent}> <Text style={[pal.text, styles.searchHistoryTitle]}> - Recent Searches + <Trans>Recent Searches</Trans> </Text> {searchHistory.map((historyItem, index) => ( <View key={index} style={styles.historyItemContainer}> diff --git a/src/view/screens/Settings/ExportCarDialog.tsx b/src/view/screens/Settings/ExportCarDialog.tsx index dca51c0dc..ba8fad2df 100644 --- a/src/view/screens/Settings/ExportCarDialog.tsx +++ b/src/view/screens/Settings/ExportCarDialog.tsx @@ -78,8 +78,9 @@ export function ExportCarDialog({ <InlineLink to="https://docs.bsky.app/blog/repo-export" style={[a.text_sm]}> - this blogpost. + this blogpost </InlineLink> + . </Trans> </P> diff --git a/src/view/screens/Settings/index.tsx b/src/view/screens/Settings/index.tsx index 00b507a99..465007777 100644 --- a/src/view/screens/Settings/index.tsx +++ b/src/view/screens/Settings/index.tsx @@ -68,6 +68,7 @@ import {SelectableBtn} from 'view/com/util/forms/SelectableBtn' import {AccountDropdownBtn} from 'view/com/util/AccountDropdownBtn' import {SimpleViewHeader} from 'view/com/util/SimpleViewHeader' import {ExportCarDialog} from './ExportCarDialog' +import {BirthDateSettingsDialog} from '#/components/dialogs/BirthDateSettings' function SettingsAccountCard({account}: {account: SessionAccount}) { const pal = usePalette('default') @@ -81,7 +82,11 @@ function SettingsAccountCard({account}: {account: SessionAccount}) { const contents = ( <View style={[pal.view, styles.linkCard]}> <View style={styles.avi}> - <UserAvatar size={40} avatar={profile?.avatar} /> + <UserAvatar + size={40} + avatar={profile?.avatar} + type={profile?.associated?.labeler ? 'labeler' : 'user'} + /> </View> <View style={[s.flex1]}> <Text type="md-bold" style={pal.text}> @@ -159,6 +164,7 @@ export function SettingsScreen({}: Props) { const {setShowLoggedOut} = useLoggedOutViewControls() const closeAllActiveElements = useCloseAllActiveElements() const exportCarControl = useDialogControl() + const birthdayControl = useDialogControl() // const primaryBg = useCustomPalette<ViewStyle>({ // light: {backgroundColor: colors.blue0}, @@ -261,6 +267,10 @@ export function SettingsScreen({}: Props) { navigation.navigate('Debug') }, [navigation]) + const onPressDebugModeration = React.useCallback(() => { + navigation.navigate('DebugMod') + }, [navigation]) + const onPressSavedFeeds = React.useCallback(() => { navigation.navigate('SavedFeeds') }, [navigation]) @@ -269,6 +279,10 @@ export function SettingsScreen({}: Props) { Linking.openURL(STATUS_PAGE_URL) }, []) + const onPressBirthday = React.useCallback(() => { + birthdayControl.open() + }, [birthdayControl]) + const clearAllStorage = React.useCallback(async () => { await clearStorage() Toast.show(_(msg`Storage cleared, you need to restart the app now.`)) @@ -281,6 +295,7 @@ export function SettingsScreen({}: Props) { return ( <View style={s.hContentRegion} testID="settingsScreen"> <ExportCarDialog control={exportCarControl} /> + <BirthDateSettingsDialog control={birthdayControl} /> <SimpleViewHeader showBackButton={isMobile} @@ -339,7 +354,7 @@ export function SettingsScreen({}: Props) { <Text type="lg-medium" style={pal.text}> <Trans>Birthday:</Trans>{' '} </Text> - <Link onPress={() => openModal({name: 'birth-date-settings'})}> + <Link onPress={onPressBirthday}> <Text type="lg" style={pal.link}> <Trans>Show</Trans> </Text> @@ -472,20 +487,20 @@ export function SettingsScreen({}: Props) { label={_(msg`System`)} left onSelect={() => setColorMode('system')} - accessibilityHint={_(msg`Set color theme to system setting`)} + accessibilityHint={_(msg`Sets color theme to system setting`)} /> <SelectableBtn selected={colorMode === 'light'} label={_(msg`Light`)} onSelect={() => setColorMode('light')} - accessibilityHint={_(msg`Set color theme to light`)} + accessibilityHint={_(msg`Sets color theme to light`)} /> <SelectableBtn selected={colorMode === 'dark'} label={_(msg`Dark`)} right onSelect={() => setColorMode('dark')} - accessibilityHint={_(msg`Set color theme to dark`)} + accessibilityHint={_(msg`Sets color theme to dark`)} /> </View> </View> @@ -504,14 +519,14 @@ export function SettingsScreen({}: Props) { label={_(msg`Dim`)} left onSelect={() => setDarkTheme('dim')} - accessibilityHint={_(msg`Set dark theme to the dim theme`)} + accessibilityHint={_(msg`Sets dark theme to the dim theme`)} /> <SelectableBtn selected={darkTheme === 'dark'} label={_(msg`Dark`)} right onSelect={() => setDarkTheme('dark')} - accessibilityHint={_(msg`Set dark theme to the dark theme`)} + accessibilityHint={_(msg`Sets dark theme to the dark theme`)} /> </View> </View> @@ -531,8 +546,8 @@ export function SettingsScreen({}: Props) { ]} onPress={openFollowingFeedPreferences} accessibilityRole="button" - accessibilityHint="" - accessibilityLabel={_(msg`Opens the home feed preferences`)}> + accessibilityLabel={_(msg`Following feed preferences`)} + accessibilityHint={_(msg`Opens the Following feed preferences`)}> <View style={[styles.iconContainer, pal.btn]}> <FontAwesomeIcon icon="sliders" @@ -552,8 +567,8 @@ export function SettingsScreen({}: Props) { ]} onPress={openThreadsPreferences} accessibilityRole="button" - accessibilityHint="" - accessibilityLabel={_(msg`Opens the threads preferences`)}> + accessibilityLabel={_(msg`Thread preferences`)} + accessibilityHint={_(msg`Opens the threads preferences`)}> <View style={[styles.iconContainer, pal.btn]}> <FontAwesomeIcon icon={['far', 'comments']} @@ -572,9 +587,10 @@ export function SettingsScreen({}: Props) { pal.view, isSwitchingAccounts && styles.dimmed, ]} - accessibilityHint="My Saved Feeds" - accessibilityLabel={_(msg`Opens screen with all saved feeds`)} - onPress={onPressSavedFeeds}> + onPress={onPressSavedFeeds} + accessibilityRole="button" + accessibilityLabel={_(msg`My saved feeds`)} + accessibilityHint={_(msg`Opens screen with all saved feeds`)}> <View style={[styles.iconContainer, pal.btn]}> <HashtagIcon style={pal.text} size={18} strokeWidth={3} /> </View> @@ -673,7 +689,7 @@ export function SettingsScreen({}: Props) { onPress={onPressAppPasswords} accessibilityRole="button" accessibilityLabel={_(msg`App password settings`)} - accessibilityHint={_(msg`Opens the app password settings page`)}> + accessibilityHint={_(msg`Opens the app password settings`)}> <View style={[styles.iconContainer, pal.btn]}> <FontAwesomeIcon icon="lock" @@ -694,7 +710,9 @@ export function SettingsScreen({}: Props) { onPress={isSwitchingAccounts ? undefined : onPressChangeHandle} accessibilityRole="button" accessibilityLabel={_(msg`Change handle`)} - accessibilityHint={_(msg`Choose a new Bluesky username or create`)}> + accessibilityHint={_( + msg`Opens modal for choosing or creating a new Bluesky username`, + )}> <View style={[styles.iconContainer, pal.btn]}> <FontAwesomeIcon icon="at" @@ -730,7 +748,9 @@ export function SettingsScreen({}: Props) { onPress={() => openModal({name: 'change-password'})} accessibilityRole="button" accessibilityLabel={_(msg`Change password`)} - accessibilityHint={_(msg`Change your Bluesky password`)}> + accessibilityHint={_( + msg`Opens modal for changing your Bluesky password`, + )}> <View style={[styles.iconContainer, pal.btn]}> <FontAwesomeIcon icon="lock" @@ -752,7 +772,7 @@ export function SettingsScreen({}: Props) { accessibilityRole="button" accessibilityLabel={_(msg`Export my data`)} accessibilityHint={_( - msg`Download Bluesky account data (repository)`, + msg`Opens modal for downloading Bluesky account data (repository)`, )}> <View style={[styles.iconContainer, pal.btn]}> <FontAwesomeIcon @@ -771,7 +791,7 @@ export function SettingsScreen({}: Props) { accessibilityRole="button" accessibilityLabel={_(msg`Delete account`)} accessibilityHint={_( - msg`Opens modal for account deletion confirmation. Requires email code.`, + msg`Opens modal for account deletion confirmation. Requires email code`, )}> <View style={[styles.iconContainer, dangerBg]}> <FontAwesomeIcon @@ -789,8 +809,8 @@ export function SettingsScreen({}: Props) { style={[pal.view, styles.linkCardNoIcon]} onPress={onPressSystemLog} accessibilityRole="button" - accessibilityHint="Open system log" - accessibilityLabel={_(msg`Opens the system log page`)}> + accessibilityLabel={_(msg`Open system log`)} + accessibilityHint={_(msg`Opens the system log page`)}> <Text type="lg" style={pal.text}> <Trans>System log</Trans> </Text> @@ -809,9 +829,19 @@ export function SettingsScreen({}: Props) { </TouchableOpacity> <TouchableOpacity style={[pal.view, styles.linkCardNoIcon]} + onPress={onPressDebugModeration} + accessibilityRole="button" + accessibilityLabel={_(msg`Open storybook page`)} + accessibilityHint={_(msg`Opens the storybook page`)}> + <Text type="lg" style={pal.text}> + <Trans>Debug Moderation</Trans> + </Text> + </TouchableOpacity> + <TouchableOpacity + style={[pal.view, styles.linkCardNoIcon]} onPress={onPressResetPreferences} accessibilityRole="button" - accessibilityLabel={_(msg`Reset preferences`)} + accessibilityLabel={_(msg`Reset preferences state`)} accessibilityHint={_(msg`Resets the preferences state`)}> <Text type="lg" style={pal.text}> <Trans>Reset preferences state</Trans> @@ -821,7 +851,7 @@ export function SettingsScreen({}: Props) { style={[pal.view, styles.linkCardNoIcon]} onPress={onPressResetOnboarding} accessibilityRole="button" - accessibilityLabel={_(msg`Reset onboarding`)} + accessibilityLabel={_(msg`Reset onboarding state`)} accessibilityHint={_(msg`Resets the onboarding state`)}> <Text type="lg" style={pal.text}> <Trans>Reset onboarding state</Trans> @@ -832,7 +862,7 @@ export function SettingsScreen({}: Props) { onPress={clearAllLegacyStorage} accessibilityRole="button" accessibilityLabel={_(msg`Clear all legacy storage data`)} - accessibilityHint={_(msg`Clear all legacy storage data`)}> + accessibilityHint={_(msg`Clears all legacy storage data`)}> <Text type="lg" style={pal.text}> <Trans> Clear all legacy storage data (restart after this) @@ -844,7 +874,7 @@ export function SettingsScreen({}: Props) { onPress={clearAllStorage} accessibilityRole="button" accessibilityLabel={_(msg`Clear all storage data`)} - accessibilityHint={_(msg`Clear all storage data`)}> + accessibilityHint={_(msg`Clears all storage data`)}> <Text type="lg" style={pal.text}> <Trans>Clear all storage data (restart after this)</Trans> </Text> @@ -933,7 +963,7 @@ function EmailConfirmationNotice() { ]} accessibilityRole="button" accessibilityLabel={_(msg`Verify my email`)} - accessibilityHint="" + accessibilityHint={_(msg`Opens modal for email verification`)} onPress={() => openModal({name: 'verify-email'})}> <FontAwesomeIcon icon="envelope" diff --git a/src/view/screens/Storybook/Buttons.tsx b/src/view/screens/Storybook/Buttons.tsx index 320db13ff..ad2fff3f4 100644 --- a/src/view/screens/Storybook/Buttons.tsx +++ b/src/view/screens/Storybook/Buttons.tsx @@ -129,6 +129,15 @@ export function Buttons() { <ButtonIcon icon={Globe} position="left" /> <ButtonText>Link out</ButtonText> </Button> + + <Button + variant="gradient" + color="gradient_sky" + size="tiny" + label="Link out"> + <ButtonIcon icon={Globe} position="left" /> + <ButtonText>Link out</ButtonText> + </Button> </View> <View style={[a.flex_row, a.gap_md, a.align_start]}> @@ -149,6 +158,14 @@ export function Buttons() { <ButtonIcon icon={ChevronLeft} /> </Button> <Button + variant="gradient" + color="gradient_sunset" + size="tiny" + shape="round" + label="Link out"> + <ButtonIcon icon={ChevronLeft} /> + </Button> + <Button variant="outline" color="primary" size="large" @@ -164,6 +181,14 @@ export function Buttons() { label="Link out"> <ButtonIcon icon={ChevronLeft} /> </Button> + <Button + variant="ghost" + color="primary" + size="tiny" + shape="round" + label="Link out"> + <ButtonIcon icon={ChevronLeft} /> + </Button> </View> <View style={[a.flex_row, a.gap_md, a.align_start]}> @@ -184,6 +209,14 @@ export function Buttons() { <ButtonIcon icon={ChevronLeft} /> </Button> <Button + variant="gradient" + color="gradient_sunset" + size="tiny" + shape="square" + label="Link out"> + <ButtonIcon icon={ChevronLeft} /> + </Button> + <Button variant="outline" color="primary" size="large" @@ -199,6 +232,14 @@ export function Buttons() { label="Link out"> <ButtonIcon icon={ChevronLeft} /> </Button> + <Button + variant="ghost" + color="primary" + size="tiny" + shape="square" + label="Link out"> + <ButtonIcon icon={ChevronLeft} /> + </Button> </View> </View> ) diff --git a/src/view/screens/Storybook/Dialogs.tsx b/src/view/screens/Storybook/Dialogs.tsx index 09be124db..c2eaf19ac 100644 --- a/src/view/screens/Storybook/Dialogs.tsx +++ b/src/view/screens/Storybook/Dialogs.tsx @@ -68,7 +68,7 @@ export function Dialogs() { </Prompt.Description> <Prompt.Actions> <Prompt.Cancel>Cancel</Prompt.Cancel> - <Prompt.Action>Confirm</Prompt.Action> + <Prompt.Action onPress={() => {}}>Confirm</Prompt.Action> </Prompt.Actions> </Prompt.Outer> diff --git a/src/view/screens/Storybook/Menus.tsx b/src/view/screens/Storybook/Menus.tsx index 082fb2b6e..2f2b14721 100644 --- a/src/view/screens/Storybook/Menus.tsx +++ b/src/view/screens/Storybook/Menus.tsx @@ -16,7 +16,7 @@ export function Menus() { <View style={[a.gap_md]}> <View style={[a.flex_row, a.align_start]}> <Menu.Root control={menuControl}> - <Menu.Trigger label="Open basic menu" style={[a.flex_1]}> + <Menu.Trigger label="Open basic menu"> {({state, props}) => { return ( <Text diff --git a/src/view/screens/Storybook/index.tsx b/src/view/screens/Storybook/index.tsx index e43d756de..3a2e2f369 100644 --- a/src/view/screens/Storybook/index.tsx +++ b/src/view/screens/Storybook/index.tsx @@ -67,6 +67,7 @@ export function Storybook() { </Button> </View> + <Dialogs /> <ThemeProvider theme="light"> <Theming /> </ThemeProvider> diff --git a/src/view/shell/Drawer.tsx b/src/view/shell/Drawer.tsx index 2a37d1fe9..1bf5647f6 100644 --- a/src/view/shell/Drawer.tsx +++ b/src/view/shell/Drawer.tsx @@ -75,6 +75,7 @@ let DrawerProfileCard = ({ avatar={profile?.avatar} // See https://github.com/bluesky-social/social-app/pull/1801: usePlainRNImage={true} + type={profile?.associated?.labeler ? 'labeler' : 'user'} /> <Text type="title-lg" @@ -93,10 +94,12 @@ let DrawerProfileCard = ({ {formatCountShortOnly(profile?.followersCount ?? 0)} </Text>{' '} {pluralize(profile?.followersCount || 0, 'follower')} ·{' '} - <Text type="xl-medium" style={pal.text}> - {formatCountShortOnly(profile?.followsCount ?? 0)} - </Text>{' '} - following + <Trans> + <Text type="xl-medium" style={pal.text}> + {formatCountShortOnly(profile?.followsCount ?? 0)} + </Text>{' '} + following + </Trans> </Text> </TouchableOpacity> ) diff --git a/src/view/shell/NavSignupCard.tsx b/src/view/shell/NavSignupCard.tsx index bae37e838..83d141498 100644 --- a/src/view/shell/NavSignupCard.tsx +++ b/src/view/shell/NavSignupCard.tsx @@ -58,7 +58,7 @@ let NavSignupCard = ({}: {}): React.ReactNode => { accessibilityHint={_(msg`Sign in`)} accessibilityLabel={_(msg`Sign in`)}> <Text type="md" style={[pal.text, s.bold]}> - Sign in + <Trans>Sign in</Trans> </Text> </Button> </View> diff --git a/src/view/shell/bottom-bar/BottomBar.tsx b/src/view/shell/bottom-bar/BottomBar.tsx index 1ab3334fa..8a19a0b4f 100644 --- a/src/view/shell/bottom-bar/BottomBar.tsx +++ b/src/view/shell/bottom-bar/BottomBar.tsx @@ -36,6 +36,7 @@ import {Button} from '#/view/com/util/forms/Button' import {s} from 'lib/styles' import {Logo} from '#/view/icons/Logo' import {Logotype} from '#/view/icons/Logotype' +import {useDedupe} from 'lib/hooks/useDedupe' type TabOptions = 'Home' | 'Search' | 'Notifications' | 'MyProfile' | 'Feeds' @@ -54,6 +55,7 @@ export function BottomBar({navigation}: BottomTabBarProps) { const {data: profile} = useProfileQuery({did: currentAccount?.did}) const {requestSwitchToAccount} = useLoggedOutViewControls() const closeAllActiveElements = useCloseAllActiveElements() + const dedupe = useDedupe() const showSignIn = React.useCallback(() => { closeAllActiveElements() @@ -74,12 +76,12 @@ export function BottomBar({navigation}: BottomTabBarProps) { if (tabState === TabState.InsideAtRoot) { emitSoftReset() } else if (tabState === TabState.Inside) { - navigation.dispatch(StackActions.popToTop()) + dedupe(() => navigation.dispatch(StackActions.popToTop())) } else { - navigation.navigate(`${tab}Tab`) + dedupe(() => navigation.navigate(`${tab}Tab`)) } }, - [track, navigation], + [track, navigation, dedupe], ) const onPressHome = React.useCallback(() => onPressTab('Home'), [onPressTab]) const onPressSearch = React.useCallback( @@ -227,6 +229,7 @@ export function BottomBar({navigation}: BottomTabBarProps) { size={27} // See https://github.com/bluesky-social/social-app/pull/1801: usePlainRNImage={true} + type={profile?.associated?.labeler ? 'labeler' : 'user'} /> </View> ) : ( @@ -236,6 +239,7 @@ export function BottomBar({navigation}: BottomTabBarProps) { size={28} // See https://github.com/bluesky-social/social-app/pull/1801: usePlainRNImage={true} + type={profile?.associated?.labeler ? 'labeler' : 'user'} /> </View> )} diff --git a/src/view/shell/desktop/LeftNav.tsx b/src/view/shell/desktop/LeftNav.tsx index c56ba941e..097ca2fbf 100644 --- a/src/view/shell/desktop/LeftNav.tsx +++ b/src/view/shell/desktop/LeftNav.tsx @@ -64,7 +64,11 @@ function ProfileCard() { style={[styles.profileCard, !isDesktop && styles.profileCardTablet]} title={_(msg`My Profile`)} asAnchor> - <UserAvatar avatar={profile.avatar} size={size} /> + <UserAvatar + avatar={profile.avatar} + size={size} + type={profile?.associated?.labeler ? 'labeler' : 'user'} + /> </Link> ) : ( <View style={[styles.profileCard, !isDesktop && styles.profileCardTablet]}> diff --git a/src/view/shell/desktop/Search.tsx b/src/view/shell/desktop/Search.tsx index 4a9483733..0c5bd452f 100644 --- a/src/view/shell/desktop/Search.tsx +++ b/src/view/shell/desktop/Search.tsx @@ -11,7 +11,7 @@ import {useNavigation, StackActions} from '@react-navigation/native' import { AppBskyActorDefs, moderateProfile, - ProfileModeration, + ModerationDecision, } from '@atproto/api' import {Trans, msg} from '@lingui/macro' import {useLingui} from '@lingui/react' @@ -86,7 +86,7 @@ export function SearchProfileCard({ moderation, }: { profile: AppBskyActorDefs.ProfileViewBasic - moderation: ProfileModeration + moderation: ModerationDecision }) { const pal = usePalette('default') @@ -111,7 +111,8 @@ export function SearchProfileCard({ <UserAvatar size={40} avatar={profile.avatar} - moderation={moderation.avatar} + moderation={moderation.ui('avatar')} + type={profile.associated?.labeler ? 'labeler' : 'user'} /> <View style={{flex: 1}}> <Text @@ -121,7 +122,7 @@ export function SearchProfileCard({ lineHeight={1.2}> {sanitizeDisplayName( profile.displayName || sanitizeHandle(profile.handle), - moderation.profile, + moderation.ui('displayName'), )} </Text> <Text type="md" style={[pal.textLight]} numberOfLines={1}> diff --git a/src/view/shell/index.tsx b/src/view/shell/index.tsx index 76a7f8fb3..f29183095 100644 --- a/src/view/shell/index.tsx +++ b/src/view/shell/index.tsx @@ -101,8 +101,8 @@ function ShellInner() { <Composer winHeight={winDim.height} /> <ModalsContainer /> <MutedWordsDialog /> - <PortalOutlet /> <Lightbox /> + <PortalOutlet /> </> ) } diff --git a/src/view/shell/index.web.tsx b/src/view/shell/index.web.tsx index 71dccb8c4..02993ac46 100644 --- a/src/view/shell/index.web.tsx +++ b/src/view/shell/index.web.tsx @@ -1,5 +1,9 @@ import React, {useEffect} from 'react' import {View, StyleSheet, TouchableOpacity} from 'react-native' +import {useNavigation} from '@react-navigation/native' +import {msg} from '@lingui/macro' +import {useLingui} from '@lingui/react' + import {ErrorBoundary} from '../com/util/ErrorBoundary' import {Lightbox} from '../com/lightbox/Lightbox' import {ModalsContainer} from '../com/modals/Modal' @@ -9,9 +13,7 @@ import {s, colors} from 'lib/styles' import {RoutesContainer, FlatNavigator} from '../../Navigation' import {DrawerContent} from './Drawer' import {useWebMediaQueries} from '../../lib/hooks/useWebMediaQueries' -import {useNavigation} from '@react-navigation/native' import {NavigationProp} from 'lib/routes/types' -import {t} from '@lingui/macro' import {useIsDrawerOpen, useSetDrawerOpen} from '#/state/shell' import {useCloseAllActiveElements} from '#/state/util' import {useWebBodyScrollLock} from '#/lib/hooks/useWebBodyScrollLock' @@ -24,6 +26,7 @@ function ShellInner() { const {isDesktop} = useWebMediaQueries() const navigator = useNavigation<NavigationProp>() const closeAllActiveElements = useCloseAllActiveElements() + const {_} = useLingui() useWebBodyScrollLock(isDrawerOpen) @@ -42,14 +45,15 @@ function ShellInner() { <Composer winHeight={0} /> <ModalsContainer /> <MutedWordsDialog /> - <PortalOutlet /> <Lightbox /> + <PortalOutlet /> + {!isDesktop && isDrawerOpen && ( <TouchableOpacity onPress={() => setDrawerOpen(false)} style={styles.drawerMask} - accessibilityLabel={t`Close navigation footer`} - accessibilityHint={t`Closes bottom navigation bar`}> + accessibilityLabel={_(msg`Close navigation footer`)} + accessibilityHint={_(msg`Closes bottom navigation bar`)}> <View style={styles.drawerContainer}> <DrawerContent /> </View> |