Bluesky app fork with some witchin' additions 💫

Add plural formatting, translate and tweak some accessibility strings in composer (#7997)

* add plural formatting and translate accessibility strings

* tweak accessibility label and add comments for translators

* fix

* tweak comments

* make label conditionally plural

* rm stray bracket

* try to fix prettier

* nope

* lint

* more lint

* prettier

---------

Co-authored-by: Hailey <me@haileyok.com>

authored by

surfdude29
Hailey
and committed by
GitHub
4a7fa07e 0897a692

+71 -26
+69 -24
src/view/com/composer/Composer.tsx
··· 12 12 BackHandler, 13 13 Keyboard, 14 14 KeyboardAvoidingView, 15 - LayoutChangeEvent, 15 + type LayoutChangeEvent, 16 16 ScrollView, 17 - StyleProp, 17 + type StyleProp, 18 18 StyleSheet, 19 19 View, 20 - ViewStyle, 20 + type ViewStyle, 21 21 } from 'react-native' 22 22 // @ts-expect-error no type definition 23 23 import ProgressCircle from 'react-native-progress/Circle' 24 24 import Animated, { 25 - AnimatedRef, 25 + type AnimatedRef, 26 26 Easing, 27 27 FadeIn, 28 28 FadeOut, ··· 41 41 ZoomOut, 42 42 } from 'react-native-reanimated' 43 43 import {useSafeAreaInsets} from 'react-native-safe-area-context' 44 - import {ImagePickerAsset} from 'expo-image-picker' 44 + import {type ImagePickerAsset} from 'expo-image-picker' 45 45 import { 46 46 AppBskyFeedDefs, 47 - AppBskyFeedGetPostThread, 48 - BskyAgent, 49 - RichText, 47 + type AppBskyFeedGetPostThread, 48 + type BskyAgent, 49 + type RichText, 50 50 } from '@atproto/api' 51 51 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' 52 - import {msg, Trans} from '@lingui/macro' 52 + import {msg, plural, Trans} from '@lingui/macro' 53 53 import {useLingui} from '@lingui/react' 54 54 import {useQueryClient} from '@tanstack/react-query' 55 55 ··· 59 59 import { 60 60 MAX_GRAPHEME_LENGTH, 61 61 SUPPORTED_MIME_TYPES, 62 - SupportedMimeTypes, 62 + type SupportedMimeTypes, 63 63 } from '#/lib/constants' 64 64 import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED' 65 65 import {useEmail} from '#/lib/hooks/useEmail' ··· 75 75 import {isAndroid, isIOS, isNative, isWeb} from '#/platform/detection' 76 76 import {useDialogStateControlContext} from '#/state/dialogs' 77 77 import {emitPostCreated} from '#/state/events' 78 - import {ComposerImage, pasteImage} from '#/state/gallery' 78 + import {type ComposerImage, pasteImage} from '#/state/gallery' 79 79 import {useModalControls} from '#/state/modals' 80 80 import {useRequireAltTextEnabled} from '#/state/preferences' 81 81 import { ··· 85 85 } from '#/state/preferences/languages' 86 86 import {usePreferencesQuery} from '#/state/queries/preferences' 87 87 import {useProfileQuery} from '#/state/queries/profile' 88 - import {Gif} from '#/state/queries/tenor' 88 + import {type Gif} from '#/state/queries/tenor' 89 89 import {useAgent, useSession} from '#/state/session' 90 90 import {useComposerControls} from '#/state/shell/composer' 91 - import {ComposerOpts} from '#/state/shell/composer' 91 + import {type ComposerOpts} from '#/state/shell/composer' 92 92 import {CharProgress} from '#/view/com/composer/char-progress/CharProgress' 93 93 import {ComposerReplyTo} from '#/view/com/composer/ComposerReplyTo' 94 94 import { ··· 105 105 import {SuggestedLanguage} from '#/view/com/composer/select-language/SuggestedLanguage' 106 106 // TODO: Prevent naming components that coincide with RN primitives 107 107 // due to linting false positives 108 - import {TextInput, TextInputRef} from '#/view/com/composer/text-input/TextInput' 108 + import { 109 + TextInput, 110 + type TextInputRef, 111 + } from '#/view/com/composer/text-input/TextInput' 109 112 import {ThreadgateBtn} from '#/view/com/composer/threadgate/ThreadgateBtn' 110 113 import {SelectVideoBtn} from '#/view/com/composer/videos/SelectVideoBtn' 111 114 import {SubtitleDialogBtn} from '#/view/com/composer/videos/SubtitleDialog' ··· 126 129 import {Text as NewText} from '#/components/Typography' 127 130 import {BottomSheetPortalProvider} from '../../../../modules/bottom-sheet' 128 131 import { 129 - ComposerAction, 132 + type ComposerAction, 130 133 composerReducer, 131 134 createComposerState, 132 - EmbedDraft, 135 + type EmbedDraft, 133 136 MAX_IMAGES, 134 - PostAction, 135 - PostDraft, 136 - ThreadDraft, 137 + type PostAction, 138 + type PostDraft, 139 + type ThreadDraft, 137 140 } from './state/composer' 138 - import {NO_VIDEO, NoVideoState, processVideo, VideoState} from './state/video' 141 + import { 142 + NO_VIDEO, 143 + type NoVideoState, 144 + processVideo, 145 + type VideoState, 146 + } from './state/video' 139 147 import {getVideoMetadata} from './videos/pickVideo' 140 148 import {clearThumbnailCache} from './videos/VideoTranscodeBackdrop' 141 149 ··· 835 843 accessible={true} 836 844 accessibilityLabel={_(msg`Write post`)} 837 845 accessibilityHint={_( 838 - msg`Compose posts up to ${MAX_GRAPHEME_LENGTH} characters in length`, 846 + msg`Compose posts up to ${plural(MAX_GRAPHEME_LENGTH || 0, { 847 + other: '# characters', 848 + })} in length`, 839 849 )} 840 850 /> 841 851 </View> ··· 917 927 children?: React.ReactNode 918 928 }) { 919 929 const pal = usePalette('default') 930 + const {_} = useLingui() 920 931 return ( 921 932 <Animated.View 922 933 style={topBarAnimatedStyle} 923 934 layout={native(LinearTransition)}> 924 935 <View style={styles.topbarInner}> 925 936 <Button 926 - label="Cancel" 937 + label={_(msg`Cancel`)} 927 938 variant="ghost" 928 939 color="primary" 929 940 shape="default" 930 941 size="small" 931 942 style={[a.rounded_full, a.py_sm, {paddingLeft: 7, paddingRight: 7}]} 932 943 onPress={onCancel} 933 - accessibilityHint="Closes post composer and discards post draft"> 944 + accessibilityHint={_( 945 + msg`Closes post composer and discards post draft`, 946 + )}> 934 947 <ButtonText style={[a.text_md]}> 935 948 <Trans>Cancel</Trans> 936 949 </ButtonText> ··· 946 959 ) : ( 947 960 <Button 948 961 testID="composerPublishBtn" 949 - label={isReply ? 'Publish reply' : 'Publish post'} 962 + label={ 963 + isReply 964 + ? isThread 965 + ? _( 966 + msg({ 967 + message: 'Publish replies', 968 + comment: 969 + 'Accessibility label for button to publish multiple replies in a thread', 970 + }), 971 + ) 972 + : _( 973 + msg({ 974 + message: 'Publish reply', 975 + comment: 976 + 'Accessibility label for button to publish a single reply', 977 + }), 978 + ) 979 + : isThread 980 + ? _( 981 + msg({ 982 + message: 'Publish posts', 983 + comment: 984 + 'Accessibility label for button to publish multiple posts in a thread', 985 + }), 986 + ) 987 + : _( 988 + msg({ 989 + message: 'Publish post', 990 + comment: 991 + 'Accessibility label for button to publish a single post', 992 + }), 993 + ) 994 + } 950 995 variant="solid" 951 996 color="primary" 952 997 shape="default"
+2 -2
src/view/com/composer/labels/LabelsBtn.tsx
··· 113 113 </Text> 114 114 <Text style={[t.atoms.text_contrast_medium, a.leading_snug]}> 115 115 <Trans> 116 - Please add any content warning labels that are applicable for 117 - the media you are posting. 116 + Please add any content warning labels that are applicable for the 117 + media you are posting. 118 118 </Trans> 119 119 </Text> 120 120 </View>