refactor: consistent localized formatting

This commit is contained in:
Mary
2024-05-30 06:52:23 +07:00
committed by Eric Bailey
parent 4d39ef2e19
commit 6f0764de1d
11 changed files with 46 additions and 71 deletions
@@ -358,7 +358,7 @@ function Inner({
hide: () => void
}) {
const t = useTheme()
const {_} = useLingui()
const {_, i18n} = useLingui()
const {currentAccount} = useSession()
const moderation = React.useMemo(
() => moderateProfile(profile, moderationOpts),
@@ -371,8 +371,8 @@ function Inner({
logContext: 'ProfileHoverCard',
})
const blockHide = profile.viewer?.blocking || profile.viewer?.blockedBy
const following = formatCount(profile.followsCount || 0)
const followers = formatCount(profile.followersCount || 0)
const following = formatCount(i18n, profile.followsCount || 0)
const followers = formatCount(i18n, profile.followersCount || 0)
const pluralizedFollowers = plural(profile.followersCount || 0, {
one: 'follower',
other: 'followers',
+6 -6
View File
@@ -130,7 +130,7 @@ let MessageItemMetadata = ({
style: StyleProp<TextStyle>
}): React.ReactNode => {
const t = useTheme()
const {_} = useLingui()
const {_, i18n} = useLingui()
const {message} = item
const handleRetry = useCallback(
@@ -149,10 +149,10 @@ let MessageItemMetadata = ({
const date = new Date(timestamp)
const now = new Date()
const time = new Intl.DateTimeFormat(undefined, {
const time = i18n.date(date, {
hour: 'numeric',
minute: 'numeric',
}).format(date)
})
const diff = now.getTime() - date.getTime()
@@ -174,15 +174,15 @@ let MessageItemMetadata = ({
return _(msg`Yesterday, ${time}`)
}
return new Intl.DateTimeFormat(undefined, {
return i18n.date(date, {
hour: 'numeric',
minute: 'numeric',
day: 'numeric',
month: 'numeric',
year: 'numeric',
}).format(date)
})
},
[_],
[_, i18n],
)
return (
@@ -1,12 +1,12 @@
import React from 'react'
import {Pressable, View} from 'react-native'
import {useLingui} from '@lingui/react'
import {android, atoms as a, useTheme, web} from '#/alf'
import * as TextField from '#/components/forms/TextField'
import {useInteractionState} from '#/components/hooks/useInteractionState'
import {CalendarDays_Stroke2_Corner0_Rounded as CalendarDays} from '#/components/icons/CalendarDays'
import {Text} from '#/components/Typography'
import {localizeDate} from './utils'
// looks like a TextField.Input, but is just a button. It'll do something different on each platform on press
// iOS: open a dialog with an inline date picker
@@ -25,6 +25,7 @@ export function DateFieldButton({
isInvalid?: boolean
accessibilityHint?: string
}) {
const {i18n} = useLingui()
const t = useTheme()
const {
@@ -91,7 +92,7 @@ export function DateFieldButton({
t.atoms.text,
{lineHeight: a.text_md.fontSize * 1.1875},
]}>
{localizeDate(value)}
{i18n.date(value, {timeZone: 'UTC'})}
</Text>
</Pressable>
</View>
-11
View File
@@ -1,16 +1,5 @@
import {getLocales} from 'expo-localization'
const LOCALE = getLocales()[0]
// we need the date in the form yyyy-MM-dd to pass to the input
export function toSimpleDateString(date: Date | string): string {
const _date = typeof date === 'string' ? new Date(date) : date
return _date.toISOString().split('T')[0]
}
export function localizeDate(date: Date | string): string {
const _date = typeof date === 'string' ? new Date(date) : date
return new Intl.DateTimeFormat(LOCALE.languageTag, {
timeZone: 'UTC',
}).format(_date)
}
+4 -4
View File
@@ -17,9 +17,9 @@ export function ProfileHeaderMetrics({
profile: Shadow<AppBskyActorDefs.ProfileViewDetailed>
}) {
const t = useTheme()
const {_} = useLingui()
const following = formatCount(profile.followsCount || 0)
const followers = formatCount(profile.followersCount || 0)
const {_, i18n} = useLingui()
const following = formatCount(i18n, profile.followsCount || 0)
const followers = formatCount(i18n, profile.followersCount || 0)
const pluralizedFollowers = plural(profile.followersCount || 0, {
one: 'follower',
other: 'followers',
@@ -54,7 +54,7 @@ export function ProfileHeaderMetrics({
</Text>
</InlineLinkText>
<Text style={[a.font_bold, t.atoms.text, a.text_md]}>
{formatCount(profile.postsCount || 0)}{' '}
{formatCount(i18n, 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>
+3 -2
View File
@@ -67,7 +67,7 @@ let FeedItem = ({
}): React.ReactNode => {
const queryClient = useQueryClient()
const pal = usePalette('default')
const {_} = useLingui()
const {_, i18n} = useLingui()
const [isAuthorsExpanded, setAuthorsExpanded] = useState<boolean>(false)
const itemHref = useMemo(() => {
if (item.type === 'post-like' || item.type === 'repost') {
@@ -175,7 +175,8 @@ let FeedItem = ({
return null
}
let formattedCount = authors.length > 1 ? formatCount(authors.length - 1) : ''
let formattedCount =
authors.length > 1 ? formatCount(i18n, authors.length - 1) : ''
return (
<Link
testID={`feedItem-by-${item.notification.author.handle}`}
+3 -3
View File
@@ -165,7 +165,7 @@ let PostThreadItemLoaded = ({
onPostReply: () => void
}): React.ReactNode => {
const pal = usePalette('default')
const {_} = useLingui()
const {_, i18n} = useLingui()
const langPrefs = useLanguagePrefs()
const {openComposer} = useComposerControls()
const [limitLines, setLimitLines] = React.useState(
@@ -339,7 +339,7 @@ let PostThreadItemLoaded = ({
type="lg"
style={pal.textLight}>
<Text type="xl-bold" style={pal.text}>
{formatCount(post.repostCount)}
{formatCount(i18n, post.repostCount)}
</Text>{' '}
<Plural
value={post.repostCount}
@@ -359,7 +359,7 @@ let PostThreadItemLoaded = ({
type="lg"
style={pal.textLight}>
<Text type="xl-bold" style={pal.text}>
{formatCount(post.likeCount)}
{formatCount(i18n, post.likeCount)}
</Text>{' '}
<Plural value={post.likeCount} one="like" other="likes" />
</Text>
+12 -16
View File
@@ -1,19 +1,18 @@
import React, {useState, useCallback} from 'react'
import React, {useCallback, useState} from 'react'
import {StyleProp, StyleSheet, TextStyle, View, ViewStyle} from 'react-native'
import DatePicker from 'react-native-date-picker'
import {
FontAwesomeIcon,
FontAwesomeIconStyle,
} from '@fortawesome/react-native-fontawesome'
import {isIOS, isAndroid} from 'platform/detection'
import {Button, ButtonType} from './Button'
import {Text} from '../text/Text'
import {useLingui} from '@lingui/react'
import {usePalette} from 'lib/hooks/usePalette'
import {TypographyVariant} from 'lib/ThemeContext'
import {useTheme} from 'lib/ThemeContext'
import {usePalette} from 'lib/hooks/usePalette'
import {getLocales} from 'expo-localization'
import DatePicker from 'react-native-date-picker'
const LOCALE = getLocales()[0]
import {isAndroid, isIOS} from 'platform/detection'
import {Text} from '../text/Text'
import {Button, ButtonType} from './Button'
interface Props {
testID?: string
@@ -30,16 +29,11 @@ interface Props {
}
export function DateInput(props: Props) {
const {i18n} = useLingui()
const [show, setShow] = useState(false)
const theme = useTheme()
const pal = usePalette('default')
const formatter = React.useMemo(() => {
return new Intl.DateTimeFormat(LOCALE.languageTag, {
timeZone: props.handleAsUTC ? 'UTC' : undefined,
})
}, [props.handleAsUTC])
const onChangeInternal = useCallback(
(date: Date) => {
setShow(false)
@@ -74,7 +68,9 @@ export function DateInput(props: Props) {
<Text
type={props.buttonLabelType}
style={[pal.text, props.buttonLabelStyle]}>
{formatter.format(props.value)}
{i18n.date(props.value, {
timeZone: props.handleAsUTC ? 'UTC' : undefined,
})}
</Text>
</View>
</Button>
+5 -12
View File
@@ -1,19 +1,12 @@
export const formatCount = (num: number) =>
Intl.NumberFormat('en-US', {
import type {I18n} from '@lingui/core'
export const formatCount = (i18n: I18n, num: number) => {
return i18n.number(num, {
notation: 'compact',
maximumFractionDigits: 1,
// `1,953` shouldn't be rounded up to 2k, it should be truncated.
// @ts-expect-error: `roundingMode` doesn't seem to be in the typings yet
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/NumberFormat/NumberFormat#roundingmode
roundingMode: 'trunc',
}).format(num)
export function formatCountShortOnly(num: number): string {
if (num >= 1000000) {
return (num / 1000000).toFixed(1) + 'M'
}
if (num >= 1000) {
return (num / 1000).toFixed(1) + 'K'
}
return String(num)
})
}
+3 -8
View File
@@ -18,7 +18,6 @@ import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
import {CommonNavigatorParams} from '#/lib/routes/types'
import {cleanError} from '#/lib/strings/errors'
import {useModalControls} from '#/state/modals'
import {useLanguagePrefs} from '#/state/preferences'
import {
useAppPasswordDeleteMutation,
useAppPasswordsQuery,
@@ -218,9 +217,8 @@ function AppPassword({
privileged?: boolean
}) {
const pal = usePalette('default')
const {_} = useLingui()
const {_, i18n} = useLingui()
const control = useDialogControl()
const {contentLanguages} = useLanguagePrefs()
const deleteMutation = useAppPasswordDeleteMutation()
const onDelete = React.useCallback(async () => {
@@ -232,9 +230,6 @@ function AppPassword({
control.open()
}, [control])
const primaryLocale =
contentLanguages.length > 0 ? contentLanguages[0] : 'en-US'
return (
<TouchableOpacity
testID={testID}
@@ -250,14 +245,14 @@ function AppPassword({
<Text type="md" style={[pal.text, styles.pr10]} numberOfLines={1}>
<Trans>
Created{' '}
{Intl.DateTimeFormat(primaryLocale, {
{i18n.date(createdAt, {
year: 'numeric',
month: 'numeric',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
}).format(new Date(createdAt))}
})}
</Trans>
</Text>
{privileged && (
+4 -4
View File
@@ -33,7 +33,7 @@ import {colors, s} from 'lib/styles'
import {useTheme} from 'lib/ThemeContext'
import {isWeb} from 'platform/detection'
import {NavSignupCard} from '#/view/shell/NavSignupCard'
import {formatCountShortOnly} from 'view/com/util/numeric/format'
import {formatCount} from 'view/com/util/numeric/format'
import {Text} from 'view/com/util/text/Text'
import {UserAvatar} from 'view/com/util/UserAvatar'
import {useTheme as useAlfTheme} from '#/alf'
@@ -68,7 +68,7 @@ let DrawerProfileCard = ({
account: SessionAccount
onPressProfile: () => void
}): React.ReactNode => {
const {_} = useLingui()
const {_, i18n} = useLingui()
const pal = usePalette('default')
const {data: profile} = useProfileQuery({did: account.did})
@@ -100,7 +100,7 @@ let DrawerProfileCard = ({
<Text type="xl" style={[pal.textLight, styles.profileCardFollowers]}>
<Trans>
<Text type="xl-medium" style={pal.text}>
{formatCountShortOnly(profile?.followersCount ?? 0)}
{formatCount(i18n, profile?.followersCount ?? 0)}
</Text>{' '}
<Plural
value={profile?.followersCount || 0}
@@ -111,7 +111,7 @@ let DrawerProfileCard = ({
&middot;{' '}
<Trans>
<Text type="xl-medium" style={pal.text}>
{formatCountShortOnly(profile?.followsCount ?? 0)}
{formatCount(i18n, profile?.followsCount ?? 0)}
</Text>{' '}
<Plural
value={profile?.followsCount || 0}