Replace pluralize by plural by @tkusano (#3882)

* Replace pluralize with plural or Plural
* Replace all pluralize (defined by src/lib/strings/helpers.ts) with plural or Plural (defined by @lingui/macro) to make some UI elements translatable.
* Delete pluralize() and related test.

* Import @formatjs polyfill libraries for plural on ios and android

- ios and andorid: import `@formtjs/intl-locale` and `@formatjs/intl-pluralrules` to polyfill `Intl.Locale` and `Intl.PluralRules` which are used in `plural()` and '<Plural />'.
- update `plural` use in notification messages for better translation.

* Rewrite to pass lint

* Add Catalan plural polyfill

* more replacement

* import zh plural data for zh-CN

* Refactor feed header components (#2964)

* Move home-related files to view/com/home

* Add HomeHeader in front of FeedTabBar

* Move isDekstop check outside FeedsTabBar

* Remove PWI logic from tabbar

* Separate platform-specific layout from shared logic

* Rename Home Feed Prefs to Following Feed Prefs (#2965)

* use `useOpenLink` hook for links in ALF (#2975)

* use `useOpenLink` hook for links in ALF

* web only for `outline`

* increase timeout to 15s (#2958)

* Normalize relative day (#2874)

* fix: normalize relative date

* chore: add comments

* refactor: skip flooring normalized diff

* refactor: let -> const

* fix: get own copy of date to prevent mutating

* refactor: rounding does the same trick

* Add handle validation to create account UI (#2959)

* show uiState errors in the box as well

simplify copy

update ui for only letters and numbers

add ui validation to handle selection

* simplify names

* Fix accidental text-node render

---------

Co-authored-by: Paul Frazee <pfrazee@gmail.com>

* Make dim theme dim (#2966)

* Make dim color scheme dim

* Tweaks

* Overall tweaks

* We have to go darker

* Tweak saturation of blues in dim

* Increase contrast on dark-dark mode

* adjust dim

---------

Co-authored-by: Eric Bailey <git@esb.lol>
Co-authored-by: Paul Frazee <pfrazee@gmail.com>
Co-authored-by: Hailey <me@haileyok.com>

* Fix dim mode unread notif color

* use `showControls` to show/hide live text icon on ios (#2982)

* Update .po files

* fix reversed icons in validator 🤦 (#2991)

* Adjust `windowSize` on `PostThread` `FlatList` (#2989)

* adjust window size, cells batching period

* rm batching period change

* Pluralize 'follow(s)'

* Include a space between the msgid count and "follower(s)/following(s)" so the translator can adjust the translated count line to fit within the Drawer.

* pluralie '# following'

* Fix & Update

* Rewrite to use Plural

* rmeove unused import

* When commiting changes, disable 'simple-import-sort' plugin in .eslintrc.js to sync with bluesky-social:main

* Revert simple-import-sort/imports related changes

* Move ProfileHoverCard web to plural util

* Followings -> following

* Add plural following to hovercard

* Followings -> Following

---------

Co-authored-by: Takayuki KUSANO <kusano@tkusano.jp>
Co-authored-by: Takayuki KUSANO <65759+tkusano@users.noreply.github.com>
Co-authored-by: dan <dan.abramov@gmail.com>
Co-authored-by: Hailey <me@haileyok.com>
Co-authored-by: Mary <148872143+mary-ext@users.noreply.github.com>
Co-authored-by: Eric Bailey <git@esb.lol>
This commit is contained in:
Paul Frazee 2024-05-06 16:55:57 -07:00 committed by GitHub
parent 2ca4b74955
commit 901feba6db
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 208 additions and 126 deletions

View file

@ -1,6 +1,6 @@
import React from 'react'
import {View} from 'react-native'
import {msg, Trans} from '@lingui/macro'
import {msg, Plural, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {AppBskyLabelerDefs} from '@atproto/api'
@ -13,7 +13,6 @@ 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
@ -69,9 +68,7 @@ export function LikeCount({count}: {count: number}) {
t.atoms.text_contrast_medium,
{fontWeight: '500'},
]}>
<Trans>
Liked by {count} {pluralize(count, 'user')}
</Trans>
<Plural value={count} one="Liked by # user" other="Liked by # users" />
</Text>
)
}

View file

@ -2,13 +2,12 @@ import React from 'react'
import {View} from 'react-native'
import {AppBskyActorDefs, moderateProfile, ModerationOpts} from '@atproto/api'
import {flip, offset, shift, size, useFloating} from '@floating-ui/react-dom'
import {msg, Trans} from '@lingui/macro'
import {msg, plural, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {makeProfileLink} from '#/lib/routes/links'
import {sanitizeDisplayName} from '#/lib/strings/display-names'
import {sanitizeHandle} from '#/lib/strings/handles'
import {pluralize} from '#/lib/strings/helpers'
import {useModerationOpts} from '#/state/preferences/moderation-opts'
import {usePrefetchProfileQuery, useProfileQuery} from '#/state/queries/profile'
import {useSession} from '#/state/session'
@ -371,7 +370,14 @@ function Inner({
const blockHide = 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')
const pluralizedFollowers = plural(profile.followersCount || 0, {
one: 'follower',
other: 'followers',
})
const pluralizedFollowings = plural(profile.followsCount || 0, {
one: 'following',
other: 'following',
})
const profileURL = makeProfileLink({
did: profile.did,
handle: profile.handle,
@ -448,7 +454,9 @@ function Inner({
onPress={hide}>
<Trans>
<Text style={[a.text_md, a.font_bold]}>{following} </Text>
<Text style={[t.atoms.text_contrast_medium]}>following</Text>
<Text style={[t.atoms.text_contrast_medium]}>
{pluralizedFollowings}
</Text>
</Trans>
</InlineLinkText>
</View>

View file

@ -1,7 +1,7 @@
import React from 'react'
import {StyleProp, View, ViewStyle} from 'react-native'
import {AppBskyFeedDefs, ComAtprotoLabelDefs} from '@atproto/api'
import {msg, Trans} from '@lingui/macro'
import {msg, Plural} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {useSession} from '#/state/session'
@ -39,7 +39,6 @@ export function LabelsOnMe({
return null
}
const labelTarget = isAccount ? _(msg`account`) : _(msg`content`)
return (
<View style={[a.flex_row, style]}>
<LabelsOnMeDialog control={control} subject={details} labels={labels} />
@ -54,11 +53,18 @@ export function LabelsOnMe({
}}>
<ButtonIcon position="left" icon={CircleInfo} />
<ButtonText style={[a.leading_snug]}>
{labels.length}{' '}
{labels.length === 1 ? (
<Trans>label has been placed on this {labelTarget}</Trans>
{isAccount ? (
<Plural
value={labels.length}
one="# label has been placed on this account"
other="# labels has been placed on this account"
/>
) : (
<Trans>labels have been placed on this {labelTarget}</Trans>
<Plural
value={labels.length}
one="# label has been placed on this content"
other="# labels has been placed on this content"
/>
)}
</ButtonText>
</Button>

View file

@ -1,13 +1,3 @@
export function pluralize(n: number, base: string, plural?: string): string {
if (n === 1) {
return base
}
if (plural) {
return plural
}
return base + 's'
}
export function enforceLen(
str: string,
len: number,

View file

@ -1,3 +1,7 @@
import '@formatjs/intl-locale/polyfill'
import '@formatjs/intl-pluralrules/polyfill'
import '@formatjs/intl-pluralrules/locale-data/en'
import {useEffect} from 'react'
import {i18n} from '@lingui/core'
@ -29,66 +33,82 @@ export async function dynamicActivate(locale: AppLanguage) {
switch (locale) {
case AppLanguage.ca: {
i18n.loadAndActivate({locale, messages: messagesCa})
await import('@formatjs/intl-pluralrules/locale-data/ca')
break
}
case AppLanguage.de: {
i18n.loadAndActivate({locale, messages: messagesDe})
await import('@formatjs/intl-pluralrules/locale-data/de')
break
}
case AppLanguage.es: {
i18n.loadAndActivate({locale, messages: messagesEs})
await import('@formatjs/intl-pluralrules/locale-data/es')
break
}
case AppLanguage.fi: {
i18n.loadAndActivate({locale, messages: messagesFi})
await import('@formatjs/intl-pluralrules/locale-data/fi')
break
}
case AppLanguage.fr: {
i18n.loadAndActivate({locale, messages: messagesFr})
await import('@formatjs/intl-pluralrules/locale-data/fr')
break
}
case AppLanguage.ga: {
i18n.loadAndActivate({locale, messages: messagesGa})
await import('@formatjs/intl-pluralrules/locale-data/ga')
break
}
case AppLanguage.hi: {
i18n.loadAndActivate({locale, messages: messagesHi})
await import('@formatjs/intl-pluralrules/locale-data/hi')
break
}
case AppLanguage.id: {
i18n.loadAndActivate({locale, messages: messagesId})
await import('@formatjs/intl-pluralrules/locale-data/id')
break
}
case AppLanguage.it: {
i18n.loadAndActivate({locale, messages: messagesIt})
await import('@formatjs/intl-pluralrules/locale-data/it')
break
}
case AppLanguage.ja: {
i18n.loadAndActivate({locale, messages: messagesJa})
await import('@formatjs/intl-pluralrules/locale-data/ja')
break
}
case AppLanguage.ko: {
i18n.loadAndActivate({locale, messages: messagesKo})
await import('@formatjs/intl-pluralrules/locale-data/ko')
break
}
case AppLanguage.pt_BR: {
i18n.loadAndActivate({locale, messages: messagesPt_BR})
await import('@formatjs/intl-pluralrules/locale-data/pt')
break
}
case AppLanguage.tr: {
i18n.loadAndActivate({locale, messages: messagesTr})
await import('@formatjs/intl-pluralrules/locale-data/tr')
break
}
case AppLanguage.uk: {
i18n.loadAndActivate({locale, messages: messagesUk})
await import('@formatjs/intl-pluralrules/locale-data/uk')
break
}
case AppLanguage.zh_CN: {
i18n.loadAndActivate({locale, messages: messagesZh_CN})
await import('@formatjs/intl-pluralrules/locale-data/zh')
break
}
case AppLanguage.zh_TW: {
i18n.loadAndActivate({locale, messages: messagesZh_TW})
await import('@formatjs/intl-pluralrules/locale-data/zh')
break
}
default: {

View file

@ -1,10 +1,9 @@
import React from 'react'
import {View} from 'react-native'
import {useSafeAreaInsets} from 'react-native-safe-area-context'
import {msg, Trans} from '@lingui/macro'
import {msg, plural, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {pluralize} from '#/lib/strings/helpers'
import {logger} from '#/logger'
import {isWeb} from '#/platform/detection'
import {isSessionDeactivated, useAgent, useSessionApi} from '#/state/session'
@ -205,10 +204,16 @@ function msToString(ms: number | undefined): string | undefined {
return undefined
}
// hours
return `${estimatedTimeHrs} ${pluralize(estimatedTimeHrs, 'hour')}`
return `${estimatedTimeHrs} ${plural(estimatedTimeHrs, {
one: 'hour',
other: 'hours',
})}`
}
// minutes
return `${estimatedTimeMins} ${pluralize(estimatedTimeMins, 'minute')}`
return `${estimatedTimeMins} ${plural(estimatedTimeMins, {
one: 'minute',
other: 'minutes',
})}`
}
return undefined
}

View file

@ -1,10 +1,9 @@
import React from 'react'
import {View} from 'react-native'
import {AppBskyActorDefs} from '@atproto/api'
import {msg, Trans} from '@lingui/macro'
import {msg, plural, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {pluralize} from '#/lib/strings/helpers'
import {Shadow} from '#/state/cache/types'
import {makeProfileLink} from 'lib/routes/links'
import {formatCount} from 'view/com/util/numeric/format'
@ -21,7 +20,14 @@ export function ProfileHeaderMetrics({
const {_} = useLingui()
const following = formatCount(profile.followsCount || 0)
const followers = formatCount(profile.followersCount || 0)
const pluralizedFollowers = pluralize(profile.followersCount || 0, 'follower')
const pluralizedFollowers = plural(profile.followersCount || 0, {
one: 'follower',
other: 'followers',
})
const pluralizedFollowings = plural(profile.followsCount || 0, {
one: 'following',
other: 'following',
})
return (
<View
@ -32,10 +38,12 @@ export function ProfileHeaderMetrics({
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>
<Trans>
<Text style={[a.font_bold, a.text_md]}>{followers} </Text>
<Text style={[t.atoms.text_contrast_medium, a.text_md]}>
{pluralizedFollowers}
</Text>
</Trans>
</InlineLinkText>
<InlineLinkText
testID="profileHeaderFollowsButton"
@ -45,15 +53,18 @@ export function ProfileHeaderMetrics({
<Trans>
<Text style={[a.font_bold, a.text_md]}>{following} </Text>
<Text style={[t.atoms.text_contrast_medium, a.text_md]}>
following
{pluralizedFollowings}
</Text>
</Trans>
</InlineLinkText>
<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>
<Trans>
{formatCount(profile.postsCount || 0)}{' '}
<Text
style={[t.atoms.text_contrast_medium, a.font_normal, a.text_md]}>
{plural(profile.postsCount || 0, {one: 'post', other: 'posts'})}
</Text>
</Trans>
</Text>
</View>
)

View file

@ -7,11 +7,10 @@ import {
ModerationOpts,
RichText as RichTextAPI,
} from '@atproto/api'
import {msg, Trans} from '@lingui/macro'
import {msg, Plural, plural, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {isAppLabeler} from '#/lib/moderation'
import {pluralize} from '#/lib/strings/helpers'
import {logger} from '#/logger'
import {Shadow} from '#/state/cache/types'
import {useModalControls} from '#/state/modals'
@ -283,12 +282,10 @@ let ProfileHeaderLabeler = ({
},
}}
size="tiny"
label={_(
msg`Liked by ${likeCount} ${pluralize(
likeCount,
'user',
)}`,
)}>
label={plural(likeCount, {
one: 'Liked by # user',
other: 'Liked by # users',
})}>
{({hovered, focused, pressed}) => (
<Text
style={[
@ -298,9 +295,11 @@ let ProfileHeaderLabeler = ({
(hovered || focused || pressed) &&
t.atoms.text_contrast_high,
]}>
<Trans>
Liked by {likeCount} {pluralize(likeCount, 'user')}
</Trans>
<Plural
value={likeCount}
one="Liked by # user"
other="Liked by # users"
/>
</Text>
)}
</Link>

View file

@ -6,12 +6,11 @@ import {RichText} from '#/components/RichText'
import {usePalette} from 'lib/hooks/usePalette'
import {s} from 'lib/styles'
import {UserAvatar} from '../util/UserAvatar'
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 {Trans, msg} from '@lingui/macro'
import {Trans, msg, Plural} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {
usePinFeedMutation,
@ -265,10 +264,11 @@ export function FeedSourceCardLoaded({
{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>
<Plural
value={feed.likeCount || 0}
one="Liked by # user"
other="Liked by # users"
/>
</Text>
) : null}
</Pressable>

View file

@ -22,7 +22,7 @@ import {
FontAwesomeIconStyle,
Props,
} from '@fortawesome/react-native-fontawesome'
import {msg, Trans} from '@lingui/macro'
import {msg, plural, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {useQueryClient} from '@tanstack/react-query'
@ -33,7 +33,6 @@ import {HeartIconSolid} from 'lib/icons'
import {makeProfileLink} from 'lib/routes/links'
import {sanitizeDisplayName} from 'lib/strings/display-names'
import {sanitizeHandle} from 'lib/strings/handles'
import {pluralize} from 'lib/strings/helpers'
import {niceDate} from 'lib/strings/time'
import {colors, s} from 'lib/styles'
import {isWeb} from 'platform/detection'
@ -176,6 +175,7 @@ let FeedItem = ({
return null
}
let formattedCount = authors.length > 1 ? formatCount(authors.length - 1) : ''
return (
<Link
testID={`feedItem-by-${item.notification.author.handle}`}
@ -236,8 +236,10 @@ let FeedItem = ({
<Trans>and</Trans>{' '}
</Text>
<Text style={[pal.text, s.bold]}>
{formatCount(authors.length - 1)}{' '}
{pluralize(authors.length - 1, 'other')}
{plural(authors.length - 1, {
one: `${formattedCount} other`,
other: `${formattedCount} others`,
})}
</Text>
</>
) : undefined}

View file

@ -8,7 +8,7 @@ import {
RichText as RichTextAPI,
} from '@atproto/api'
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 {moderatePost_wrapped as moderatePost} from '#/lib/moderatePost_wrapped'
@ -24,7 +24,7 @@ import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
import {makeProfileLink} from 'lib/routes/links'
import {sanitizeDisplayName} from 'lib/strings/display-names'
import {sanitizeHandle} from 'lib/strings/handles'
import {countLines, pluralize} from 'lib/strings/helpers'
import {countLines} from 'lib/strings/helpers'
import {niceDate} from 'lib/strings/time'
import {s} from 'lib/styles'
import {isWeb} from 'platform/detection'
@ -336,7 +336,11 @@ let PostThreadItemLoaded = ({
<Text type="xl-bold" style={pal.text}>
{formatCount(post.repostCount)}
</Text>{' '}
{pluralize(post.repostCount, 'repost')}
<Plural
value={post.repostCount}
one="repost"
other="reposts"
/>
</Text>
</Link>
) : null}
@ -352,7 +356,7 @@ let PostThreadItemLoaded = ({
<Text type="xl-bold" style={pal.text}>
{formatCount(post.likeCount)}
</Text>{' '}
{pluralize(post.likeCount, 'like')}
<Plural value={post.likeCount} one="like" other="likes" />
</Text>
</Link>
) : null}

View file

@ -12,14 +12,13 @@ import {
AtUri,
RichText as RichTextAPI,
} from '@atproto/api'
import {msg} from '@lingui/macro'
import {msg, plural} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {HITSLOP_10, HITSLOP_20} from '#/lib/constants'
import {CommentBottomArrow, HeartIcon, HeartIconSolid} from '#/lib/icons'
import {makeProfileLink} from '#/lib/routes/links'
import {shareUrl} from '#/lib/sharing'
import {pluralize} from '#/lib/strings/helpers'
import {toShareUrl} from '#/lib/strings/url-helpers'
import {s} from '#/lib/styles'
import {useTheme} from '#/lib/ThemeContext'
@ -159,9 +158,10 @@ let PostCtrls = ({
}
}}
accessibilityRole="button"
accessibilityLabel={`Reply (${post.replyCount} ${
post.replyCount === 1 ? 'reply' : 'replies'
})`}
accessibilityLabel={plural(post.replyCount || 0, {
one: 'Reply (# reply)',
other: 'Reply (# replies)',
})}
accessibilityHint=""
hitSlop={big ? HITSLOP_20 : HITSLOP_10}>
<CommentBottomArrow
@ -193,9 +193,17 @@ let PostCtrls = ({
requireAuth(() => onPressToggleLike())
}}
accessibilityRole="button"
accessibilityLabel={`${
post.viewer?.like ? _(msg`Unlike`) : _(msg`Like`)
} (${post.likeCount} ${pluralize(post.likeCount || 0, 'like')})`}
accessibilityLabel={
post.viewer?.like
? plural(post.likeCount || 0, {
one: 'Unlike (# like)',
other: 'Unlike (# likes)',
})
: plural(post.likeCount || 0, {
one: 'Like (# like)',
other: 'Like (# likes)',
})
}
accessibilityHint=""
hitSlop={big ? HITSLOP_20 : HITSLOP_10}>
{post.viewer?.like ? (

View file

@ -4,11 +4,10 @@ import {RepostIcon} from 'lib/icons'
import {s, colors} from 'lib/styles'
import {useTheme} from 'lib/ThemeContext'
import {Text} from '../text/Text'
import {pluralize} from 'lib/strings/helpers'
import {HITSLOP_10, HITSLOP_20} from 'lib/constants'
import {useModalControls} from '#/state/modals'
import {useRequireAuth} from '#/state/session'
import {msg} from '@lingui/macro'
import {msg, plural} from '@lingui/macro'
import {useLingui} from '@lingui/react'
interface Props {
@ -59,7 +58,7 @@ let RepostButton = ({
isReposted
? _(msg`Undo repost`)
: _(msg({message: 'Repost', context: 'action'}))
} (${repostCount} ${pluralize(repostCount || 0, 'repost')})`}
} (${plural(repostCount || 0, {one: '# repost', other: '# reposts'})})`}
accessibilityHint=""
hitSlop={big ? HITSLOP_20 : HITSLOP_10}>
<RepostIcon

View file

@ -12,7 +12,7 @@ import {CommonNavigatorParams, NativeStackScreenProps} from 'lib/routes/types'
import {ViewHeader} from 'view/com/util/ViewHeader'
import {CenteredView} from 'view/com/util/Views'
import debounce from 'lodash.debounce'
import {Trans, msg} from '@lingui/macro'
import {Trans, msg, Plural} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {
usePreferencesQuery,
@ -27,7 +27,6 @@ function RepliesThresholdInput({
initialValue: number
}) {
const pal = usePalette('default')
const {_} = useLingui()
const [value, setValue] = useState(initialValue)
const {mutate: setFeedViewPref} = useSetFeedViewPreferencesMutation()
const preValue = React.useRef(initialValue)
@ -64,13 +63,12 @@ function RepliesThresholdInput({
thumbTintColor={colors.blue3}
/>
<Text type="xs" style={pal.text}>
{value === 0
? _(msg`Show all replies`)
: _(
msg`Show replies with at least ${value} ${
value > 1 ? `likes` : `like`
}`,
)}
<Plural
value={value}
_0="Show all replies"
one="Show replies with at least # like"
other="Show replies with at least # likes"
/>
</Text>
</View>
)

View file

@ -1,6 +1,6 @@
import React, {useCallback, useMemo} from 'react'
import {Pressable, StyleSheet, View} from 'react-native'
import {msg, Trans} from '@lingui/macro'
import {msg, Plural, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {useIsFocused, useNavigation} from '@react-navigation/native'
import {NativeStackScreenProps} from '@react-navigation/native-stack'
@ -35,7 +35,6 @@ import {makeCustomFeedLink} from 'lib/routes/links'
import {CommonNavigatorParams} from 'lib/routes/types'
import {NavigationProp} from 'lib/routes/types'
import {shareUrl} from 'lib/sharing'
import {pluralize} from 'lib/strings/helpers'
import {makeRecordUri} from 'lib/strings/url-helpers'
import {toShareUrl} from 'lib/strings/url-helpers'
import {s} from 'lib/styles'
@ -597,7 +596,11 @@ function AboutSection({
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')}`)}
<Plural
value={likeCount}
one="Liked by # user"
other="Liked by # users"
/>
</InlineLinkText>
)}
</View>

View file

@ -13,7 +13,7 @@ import {
FontAwesomeIcon,
FontAwesomeIconStyle,
} from '@fortawesome/react-native-fontawesome'
import {msg, Trans} from '@lingui/macro'
import {msg, Plural, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {StackActions, useNavigation} from '@react-navigation/native'
@ -42,7 +42,6 @@ import {
} from 'lib/icons'
import {getTabState, TabState} from 'lib/routes/helpers'
import {NavigationProp} from 'lib/routes/types'
import {pluralize} from 'lib/strings/helpers'
import {colors, s} from 'lib/styles'
import {useTheme} from 'lib/ThemeContext'
import {isWeb} from 'platform/detection'
@ -90,15 +89,26 @@ let DrawerProfileCard = ({
@{account.handle}
</Text>
<Text type="xl" style={[pal.textLight, styles.profileCardFollowers]}>
<Text type="xl-medium" style={pal.text}>
{formatCountShortOnly(profile?.followersCount ?? 0)}
</Text>{' '}
{pluralize(profile?.followersCount || 0, 'follower')} &middot;{' '}
<Trans>
<Text type="xl-medium" style={pal.text}>
{formatCountShortOnly(profile?.followersCount ?? 0)}
</Text>{' '}
<Plural
value={profile?.followersCount || 0}
one="follower"
other="followers"
/>{' '}
&middot;{' '}
</Trans>
<Trans>
<Text type="xl-medium" style={pal.text}>
{formatCountShortOnly(profile?.followsCount ?? 0)}
</Text>{' '}
following
<Plural
value={profile?.followsCount || 0}
one="following"
other="following"
/>
</Trans>
</Text>
</TouchableOpacity>