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>
This commit is contained in:
@@ -12,17 +12,17 @@ import {
|
|||||||
BackHandler,
|
BackHandler,
|
||||||
Keyboard,
|
Keyboard,
|
||||||
KeyboardAvoidingView,
|
KeyboardAvoidingView,
|
||||||
LayoutChangeEvent,
|
type LayoutChangeEvent,
|
||||||
ScrollView,
|
ScrollView,
|
||||||
StyleProp,
|
type StyleProp,
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
View,
|
View,
|
||||||
ViewStyle,
|
type ViewStyle,
|
||||||
} from 'react-native'
|
} from 'react-native'
|
||||||
// @ts-expect-error no type definition
|
// @ts-expect-error no type definition
|
||||||
import ProgressCircle from 'react-native-progress/Circle'
|
import ProgressCircle from 'react-native-progress/Circle'
|
||||||
import Animated, {
|
import Animated, {
|
||||||
AnimatedRef,
|
type AnimatedRef,
|
||||||
Easing,
|
Easing,
|
||||||
FadeIn,
|
FadeIn,
|
||||||
FadeOut,
|
FadeOut,
|
||||||
@@ -41,15 +41,15 @@ import Animated, {
|
|||||||
ZoomOut,
|
ZoomOut,
|
||||||
} from 'react-native-reanimated'
|
} from 'react-native-reanimated'
|
||||||
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
import {useSafeAreaInsets} from 'react-native-safe-area-context'
|
||||||
import {ImagePickerAsset} from 'expo-image-picker'
|
import {type ImagePickerAsset} from 'expo-image-picker'
|
||||||
import {
|
import {
|
||||||
AppBskyFeedDefs,
|
AppBskyFeedDefs,
|
||||||
AppBskyFeedGetPostThread,
|
type AppBskyFeedGetPostThread,
|
||||||
BskyAgent,
|
type BskyAgent,
|
||||||
RichText,
|
type RichText,
|
||||||
} from '@atproto/api'
|
} from '@atproto/api'
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||||
import {msg, Trans} from '@lingui/macro'
|
import {msg, plural, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
import {useQueryClient} from '@tanstack/react-query'
|
import {useQueryClient} from '@tanstack/react-query'
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ import {until} from '#/lib/async/until'
|
|||||||
import {
|
import {
|
||||||
MAX_GRAPHEME_LENGTH,
|
MAX_GRAPHEME_LENGTH,
|
||||||
SUPPORTED_MIME_TYPES,
|
SUPPORTED_MIME_TYPES,
|
||||||
SupportedMimeTypes,
|
type SupportedMimeTypes,
|
||||||
} from '#/lib/constants'
|
} from '#/lib/constants'
|
||||||
import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED'
|
import {useAnimatedScrollHandler} from '#/lib/hooks/useAnimatedScrollHandler_FIXED'
|
||||||
import {useEmail} from '#/lib/hooks/useEmail'
|
import {useEmail} from '#/lib/hooks/useEmail'
|
||||||
@@ -75,7 +75,7 @@ import {logger} from '#/logger'
|
|||||||
import {isAndroid, isIOS, isNative, isWeb} from '#/platform/detection'
|
import {isAndroid, isIOS, isNative, isWeb} from '#/platform/detection'
|
||||||
import {useDialogStateControlContext} from '#/state/dialogs'
|
import {useDialogStateControlContext} from '#/state/dialogs'
|
||||||
import {emitPostCreated} from '#/state/events'
|
import {emitPostCreated} from '#/state/events'
|
||||||
import {ComposerImage, pasteImage} from '#/state/gallery'
|
import {type ComposerImage, pasteImage} from '#/state/gallery'
|
||||||
import {useModalControls} from '#/state/modals'
|
import {useModalControls} from '#/state/modals'
|
||||||
import {useRequireAltTextEnabled} from '#/state/preferences'
|
import {useRequireAltTextEnabled} from '#/state/preferences'
|
||||||
import {
|
import {
|
||||||
@@ -85,10 +85,10 @@ import {
|
|||||||
} from '#/state/preferences/languages'
|
} from '#/state/preferences/languages'
|
||||||
import {usePreferencesQuery} from '#/state/queries/preferences'
|
import {usePreferencesQuery} from '#/state/queries/preferences'
|
||||||
import {useProfileQuery} from '#/state/queries/profile'
|
import {useProfileQuery} from '#/state/queries/profile'
|
||||||
import {Gif} from '#/state/queries/tenor'
|
import {type Gif} from '#/state/queries/tenor'
|
||||||
import {useAgent, useSession} from '#/state/session'
|
import {useAgent, useSession} from '#/state/session'
|
||||||
import {useComposerControls} from '#/state/shell/composer'
|
import {useComposerControls} from '#/state/shell/composer'
|
||||||
import {ComposerOpts} from '#/state/shell/composer'
|
import {type ComposerOpts} from '#/state/shell/composer'
|
||||||
import {CharProgress} from '#/view/com/composer/char-progress/CharProgress'
|
import {CharProgress} from '#/view/com/composer/char-progress/CharProgress'
|
||||||
import {ComposerReplyTo} from '#/view/com/composer/ComposerReplyTo'
|
import {ComposerReplyTo} from '#/view/com/composer/ComposerReplyTo'
|
||||||
import {
|
import {
|
||||||
@@ -105,7 +105,10 @@ import {SelectLangBtn} from '#/view/com/composer/select-language/SelectLangBtn'
|
|||||||
import {SuggestedLanguage} from '#/view/com/composer/select-language/SuggestedLanguage'
|
import {SuggestedLanguage} from '#/view/com/composer/select-language/SuggestedLanguage'
|
||||||
// TODO: Prevent naming components that coincide with RN primitives
|
// TODO: Prevent naming components that coincide with RN primitives
|
||||||
// due to linting false positives
|
// due to linting false positives
|
||||||
import {TextInput, TextInputRef} from '#/view/com/composer/text-input/TextInput'
|
import {
|
||||||
|
TextInput,
|
||||||
|
type TextInputRef,
|
||||||
|
} from '#/view/com/composer/text-input/TextInput'
|
||||||
import {ThreadgateBtn} from '#/view/com/composer/threadgate/ThreadgateBtn'
|
import {ThreadgateBtn} from '#/view/com/composer/threadgate/ThreadgateBtn'
|
||||||
import {SelectVideoBtn} from '#/view/com/composer/videos/SelectVideoBtn'
|
import {SelectVideoBtn} from '#/view/com/composer/videos/SelectVideoBtn'
|
||||||
import {SubtitleDialogBtn} from '#/view/com/composer/videos/SubtitleDialog'
|
import {SubtitleDialogBtn} from '#/view/com/composer/videos/SubtitleDialog'
|
||||||
@@ -126,16 +129,21 @@ import * as Prompt from '#/components/Prompt'
|
|||||||
import {Text as NewText} from '#/components/Typography'
|
import {Text as NewText} from '#/components/Typography'
|
||||||
import {BottomSheetPortalProvider} from '../../../../modules/bottom-sheet'
|
import {BottomSheetPortalProvider} from '../../../../modules/bottom-sheet'
|
||||||
import {
|
import {
|
||||||
ComposerAction,
|
type ComposerAction,
|
||||||
composerReducer,
|
composerReducer,
|
||||||
createComposerState,
|
createComposerState,
|
||||||
EmbedDraft,
|
type EmbedDraft,
|
||||||
MAX_IMAGES,
|
MAX_IMAGES,
|
||||||
PostAction,
|
type PostAction,
|
||||||
PostDraft,
|
type PostDraft,
|
||||||
ThreadDraft,
|
type ThreadDraft,
|
||||||
} from './state/composer'
|
} from './state/composer'
|
||||||
import {NO_VIDEO, NoVideoState, processVideo, VideoState} from './state/video'
|
import {
|
||||||
|
NO_VIDEO,
|
||||||
|
type NoVideoState,
|
||||||
|
processVideo,
|
||||||
|
type VideoState,
|
||||||
|
} from './state/video'
|
||||||
import {getVideoMetadata} from './videos/pickVideo'
|
import {getVideoMetadata} from './videos/pickVideo'
|
||||||
import {clearThumbnailCache} from './videos/VideoTranscodeBackdrop'
|
import {clearThumbnailCache} from './videos/VideoTranscodeBackdrop'
|
||||||
|
|
||||||
@@ -835,7 +843,9 @@ let ComposerPost = React.memo(function ComposerPost({
|
|||||||
accessible={true}
|
accessible={true}
|
||||||
accessibilityLabel={_(msg`Write post`)}
|
accessibilityLabel={_(msg`Write post`)}
|
||||||
accessibilityHint={_(
|
accessibilityHint={_(
|
||||||
msg`Compose posts up to ${MAX_GRAPHEME_LENGTH} characters in length`,
|
msg`Compose posts up to ${plural(MAX_GRAPHEME_LENGTH || 0, {
|
||||||
|
other: '# characters',
|
||||||
|
})} in length`,
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
@@ -917,20 +927,23 @@ function ComposerTopBar({
|
|||||||
children?: React.ReactNode
|
children?: React.ReactNode
|
||||||
}) {
|
}) {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
|
const {_} = useLingui()
|
||||||
return (
|
return (
|
||||||
<Animated.View
|
<Animated.View
|
||||||
style={topBarAnimatedStyle}
|
style={topBarAnimatedStyle}
|
||||||
layout={native(LinearTransition)}>
|
layout={native(LinearTransition)}>
|
||||||
<View style={styles.topbarInner}>
|
<View style={styles.topbarInner}>
|
||||||
<Button
|
<Button
|
||||||
label="Cancel"
|
label={_(msg`Cancel`)}
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
color="primary"
|
color="primary"
|
||||||
shape="default"
|
shape="default"
|
||||||
size="small"
|
size="small"
|
||||||
style={[a.rounded_full, a.py_sm, {paddingLeft: 7, paddingRight: 7}]}
|
style={[a.rounded_full, a.py_sm, {paddingLeft: 7, paddingRight: 7}]}
|
||||||
onPress={onCancel}
|
onPress={onCancel}
|
||||||
accessibilityHint="Closes post composer and discards post draft">
|
accessibilityHint={_(
|
||||||
|
msg`Closes post composer and discards post draft`,
|
||||||
|
)}>
|
||||||
<ButtonText style={[a.text_md]}>
|
<ButtonText style={[a.text_md]}>
|
||||||
<Trans>Cancel</Trans>
|
<Trans>Cancel</Trans>
|
||||||
</ButtonText>
|
</ButtonText>
|
||||||
@@ -946,7 +959,39 @@ function ComposerTopBar({
|
|||||||
) : (
|
) : (
|
||||||
<Button
|
<Button
|
||||||
testID="composerPublishBtn"
|
testID="composerPublishBtn"
|
||||||
label={isReply ? 'Publish reply' : 'Publish post'}
|
label={
|
||||||
|
isReply
|
||||||
|
? isThread
|
||||||
|
? _(
|
||||||
|
msg({
|
||||||
|
message: 'Publish replies',
|
||||||
|
comment:
|
||||||
|
'Accessibility label for button to publish multiple replies in a thread',
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
: _(
|
||||||
|
msg({
|
||||||
|
message: 'Publish reply',
|
||||||
|
comment:
|
||||||
|
'Accessibility label for button to publish a single reply',
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
: isThread
|
||||||
|
? _(
|
||||||
|
msg({
|
||||||
|
message: 'Publish posts',
|
||||||
|
comment:
|
||||||
|
'Accessibility label for button to publish multiple posts in a thread',
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
: _(
|
||||||
|
msg({
|
||||||
|
message: 'Publish post',
|
||||||
|
comment:
|
||||||
|
'Accessibility label for button to publish a single post',
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
variant="solid"
|
variant="solid"
|
||||||
color="primary"
|
color="primary"
|
||||||
shape="default"
|
shape="default"
|
||||||
|
|||||||
@@ -113,8 +113,8 @@ function DialogInner({
|
|||||||
</Text>
|
</Text>
|
||||||
<Text style={[t.atoms.text_contrast_medium, a.leading_snug]}>
|
<Text style={[t.atoms.text_contrast_medium, a.leading_snug]}>
|
||||||
<Trans>
|
<Trans>
|
||||||
Please add any content warning labels that are applicable for
|
Please add any content warning labels that are applicable for the
|
||||||
the media you are posting.
|
media you are posting.
|
||||||
</Trans>
|
</Trans>
|
||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
|
|||||||
Reference in New Issue
Block a user