Internationalization & localization (#1822)

* install and setup lingui

* setup dynamic locale activation and async loading

* first pass of automated replacement of text messages

* add some more documentaton

* fix nits

* add `es` and `hi`locales for testing purposes

* make accessibilityLabel localized

* compile and extract new messages

* fix merge conflicts

* fix eslint warning

* change instructions from sending email to opening PR

* fix comments
This commit is contained in:
Ansh 2023-11-09 10:04:16 -08:00 committed by GitHub
parent 82059b7ee1
commit 4c7850f8c4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
108 changed files with 10334 additions and 1365 deletions

View file

@ -40,6 +40,8 @@ import {makeProfileLink} from 'lib/routes/links'
import {Link} from '../util/Link'
import {ProfileHeaderSuggestedFollows} from './ProfileHeaderSuggestedFollows'
import {logger} from '#/logger'
import {Trans, msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {useModalControls} from '#/state/modals'
interface Props {
@ -114,6 +116,7 @@ const ProfileHeaderLoaded = observer(function ProfileHeaderLoadedImpl({
const pal = usePalette('default')
const palInverted = usePalette('inverted')
const store = useStores()
const {_} = useLingui()
const {openModal} = useModalControls()
const navigation = useNavigation<NavigationProp>()
const {track} = useAnalytics()
@ -369,10 +372,10 @@ const ProfileHeaderLoaded = observer(function ProfileHeaderLoadedImpl({
onPress={onPressEditProfile}
style={[styles.btn, styles.mainBtn, pal.btn]}
accessibilityRole="button"
accessibilityLabel="Edit profile"
accessibilityLabel={_(msg`Edit profile`)}
accessibilityHint="Opens editor for profile display name, avatar, background image, and description">
<Text type="button" style={pal.text}>
Edit Profile
<Trans>Edit Profile</Trans>
</Text>
</TouchableOpacity>
) : view.viewer.blocking ? (
@ -382,10 +385,10 @@ const ProfileHeaderLoaded = observer(function ProfileHeaderLoadedImpl({
onPress={onPressUnblockAccount}
style={[styles.btn, styles.mainBtn, pal.btn]}
accessibilityRole="button"
accessibilityLabel="Unblock"
accessibilityLabel={_(msg`Unblock`)}
accessibilityHint="">
<Text type="button" style={[pal.text, s.bold]}>
Unblock
<Trans>Unblock</Trans>
</Text>
</TouchableOpacity>
)
@ -439,7 +442,7 @@ const ProfileHeaderLoaded = observer(function ProfileHeaderLoadedImpl({
size={14}
/>
<Text type="button" style={pal.text}>
Following
<Trans>Following</Trans>
</Text>
</TouchableOpacity>
) : (
@ -455,7 +458,7 @@ const ProfileHeaderLoaded = observer(function ProfileHeaderLoadedImpl({
style={[palInverted.text, s.mr5]}
/>
<Text type="button" style={[palInverted.text, s.bold]}>
Follow
<Trans>Follow</Trans>
</Text>
</TouchableOpacity>
)}
@ -465,7 +468,7 @@ const ProfileHeaderLoaded = observer(function ProfileHeaderLoadedImpl({
<NativeDropdown
testID="profileHeaderDropdownBtn"
items={dropdownItems}
accessibilityLabel="More options"
accessibilityLabel={_(msg`More options`)}
accessibilityHint="">
<View style={[styles.btn, styles.secondaryBtn, pal.btn]}>
<FontAwesomeIcon icon="ellipsis" size={20} style={[pal.text]} />
@ -488,7 +491,7 @@ const ProfileHeaderLoaded = observer(function ProfileHeaderLoadedImpl({
{view.viewer.followedBy && !blockHide ? (
<View style={[styles.pill, pal.btn, s.mr5]}>
<Text type="xs" style={[pal.text]}>
Follows you
<Trans>Follows you</Trans>
</Text>
</View>
) : undefined}
@ -533,7 +536,7 @@ const ProfileHeaderLoaded = observer(function ProfileHeaderLoadedImpl({
{following}{' '}
</Text>
<Text type="md" style={[pal.textLight]}>
following
<Trans>following</Trans>
</Text>
</Link>
<Text type="md" style={[s.bold, pal.text]}>
@ -572,7 +575,7 @@ const ProfileHeaderLoaded = observer(function ProfileHeaderLoadedImpl({
onPress={onPressBack}
hitSlop={BACK_HITSLOP}
accessibilityRole="button"
accessibilityLabel="Back"
accessibilityLabel={_(msg`Back`)}
accessibilityHint="">
<View style={styles.backBtnWrapper}>
<BlurView style={styles.backBtn} blurType="dark">

View file

@ -17,6 +17,8 @@ import {NavigationProp} from 'lib/routes/types'
import {BACK_HITSLOP} from 'lib/constants'
import {isNative} from 'platform/detection'
import {ImagesLightbox} from 'state/models/ui/shell'
import {useLingui} from '@lingui/react'
import {msg} from '@lingui/macro'
import {useSetDrawerOpen} from '#/state/shell'
export const ProfileSubpageHeader = observer(function HeaderImpl({
@ -45,6 +47,7 @@ export const ProfileSubpageHeader = observer(function HeaderImpl({
const store = useStores()
const setDrawerOpen = useSetDrawerOpen()
const navigation = useNavigation<NavigationProp>()
const {_} = useLingui()
const {isMobile} = useWebMediaQueries()
const pal = usePalette('default')
const canGoBack = navigation.canGoBack()
@ -123,7 +126,7 @@ export const ProfileSubpageHeader = observer(function HeaderImpl({
testID="headerAviButton"
onPress={onPressAvi}
accessibilityRole="image"
accessibilityLabel="View the avatar"
accessibilityLabel={_(msg`View the avatar`)}
accessibilityHint=""
style={{width: 58}}>
<UserAvatar type={avatarType} size={58} avatar={avatar} />