about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/App.native.tsx7
-rw-r--r--src/Navigation.tsx79
-rw-r--r--src/view/com/auth/LoggedOut.tsx4
-rw-r--r--src/view/com/auth/SplashScreen.web.tsx2
-rw-r--r--src/view/com/auth/create/Step1.tsx5
-rw-r--r--src/view/com/auth/create/Step2.tsx12
-rw-r--r--src/view/com/auth/create/Step3.tsx2
-rw-r--r--src/view/com/auth/create/StepHeader.tsx7
-rw-r--r--src/view/com/auth/login/ChooseAccountForm.tsx8
-rw-r--r--src/view/com/auth/login/ForgotPasswordForm.tsx16
-rw-r--r--src/view/com/auth/login/LoginForm.tsx16
-rw-r--r--src/view/com/auth/login/PasswordUpdatedForm.tsx2
-rw-r--r--src/view/com/auth/login/SetNewPasswordForm.tsx12
-rw-r--r--src/view/com/auth/onboarding/RecommendedFeedsItem.tsx13
-rw-r--r--src/view/com/auth/onboarding/RecommendedFollows.tsx2
-rw-r--r--src/view/com/auth/onboarding/WelcomeDesktop.tsx24
-rw-r--r--src/view/com/composer/Composer.tsx32
-rw-r--r--src/view/com/composer/ExternalEmbed.tsx2
-rw-r--r--src/view/com/composer/Prompt.tsx2
-rw-r--r--src/view/com/composer/photos/OpenCameraBtn.tsx2
-rw-r--r--src/view/com/composer/photos/SelectPhotoBtn.tsx2
-rw-r--r--src/view/com/composer/text-input/web/Autocomplete.tsx3
-rw-r--r--src/view/com/feeds/FeedPage.tsx2
-rw-r--r--src/view/com/feeds/FeedSourceCard.tsx33
-rw-r--r--src/view/com/feeds/ProfileFeedgens.tsx10
-rw-r--r--src/view/com/lightbox/ImageViewing/components/ImageDefaultHeader.tsx2
-rw-r--r--src/view/com/lightbox/Lightbox.tsx15
-rw-r--r--src/view/com/lightbox/Lightbox.web.tsx6
-rw-r--r--src/view/com/lists/ListCard.tsx24
-rw-r--r--src/view/com/lists/ListMembers.tsx12
-rw-r--r--src/view/com/lists/ProfileLists.tsx10
-rw-r--r--src/view/com/modals/AddAppPasswords.tsx28
-rw-r--r--src/view/com/modals/AppealLabel.tsx2
-rw-r--r--src/view/com/modals/BirthDateSettings.tsx2
-rw-r--r--src/view/com/modals/ChangeEmail.tsx6
-rw-r--r--src/view/com/modals/ChangeHandle.tsx16
-rw-r--r--src/view/com/modals/Confirm.tsx10
-rw-r--r--src/view/com/modals/ContentFilteringSettings.tsx23
-rw-r--r--src/view/com/modals/CreateOrEditList.tsx45
-rw-r--r--src/view/com/modals/DeleteAccount.tsx18
-rw-r--r--src/view/com/modals/EditImage.tsx10
-rw-r--r--src/view/com/modals/EditProfile.tsx13
-rw-r--r--src/view/com/modals/InviteCodes.tsx8
-rw-r--r--src/view/com/modals/ListAddRemoveUsers.tsx6
-rw-r--r--src/view/com/modals/ModerationDetails.tsx45
-rw-r--r--src/view/com/modals/ProfilePreview.tsx11
-rw-r--r--src/view/com/modals/Repost.tsx24
-rw-r--r--src/view/com/modals/SelfLabel.tsx8
-rw-r--r--src/view/com/modals/ServerInput.tsx6
-rw-r--r--src/view/com/modals/SwitchAccount.tsx8
-rw-r--r--src/view/com/modals/Threadgate.tsx4
-rw-r--r--src/view/com/modals/UserAddRemoveLists.tsx26
-rw-r--r--src/view/com/modals/VerifyEmail.tsx34
-rw-r--r--src/view/com/modals/Waitlist.tsx16
-rw-r--r--src/view/com/notifications/Feed.tsx11
-rw-r--r--src/view/com/notifications/FeedItem.tsx25
-rw-r--r--src/view/com/pager/FeedsTabBarMobile.tsx4
-rw-r--r--src/view/com/post-thread/PostThread.tsx8
-rw-r--r--src/view/com/post-thread/PostThreadItem.tsx11
-rw-r--r--src/view/com/post/Post.tsx21
-rw-r--r--src/view/com/posts/CustomFeedEmptyState.tsx9
-rw-r--r--src/view/com/posts/Feed.tsx9
-rw-r--r--src/view/com/posts/FeedErrorMessage.tsx15
-rw-r--r--src/view/com/posts/FeedItem.tsx74
-rw-r--r--src/view/com/posts/FeedSlice.tsx3
-rw-r--r--src/view/com/posts/FollowingEmptyState.tsx13
-rw-r--r--src/view/com/posts/FollowingEndOfFeed.tsx13
-rw-r--r--src/view/com/profile/FollowButton.tsx11
-rw-r--r--src/view/com/profile/ProfileCard.tsx9
-rw-r--r--src/view/com/profile/ProfileHeader.tsx90
-rw-r--r--src/view/com/profile/ProfileHeaderSuggestedFollows.tsx3
-rw-r--r--src/view/com/profile/ProfileSubpageHeader.tsx20
-rw-r--r--src/view/com/util/AccountDropdownBtn.tsx2
-rw-r--r--src/view/com/util/Selector.tsx7
-rw-r--r--src/view/com/util/ViewHeader.tsx7
-rw-r--r--src/view/com/util/error/ErrorMessage.tsx4
-rw-r--r--src/view/com/util/error/ErrorScreen.tsx6
-rw-r--r--src/view/com/util/forms/DropdownButton.tsx8
-rw-r--r--src/view/com/util/forms/PostDropdownBtn.tsx20
-rw-r--r--src/view/com/util/forms/SearchInput.tsx2
-rw-r--r--src/view/com/util/images/AutoSizedImage.tsx5
-rw-r--r--src/view/com/util/images/Gallery.tsx5
-rw-r--r--src/view/com/util/moderation/ContentHider.tsx4
-rw-r--r--src/view/com/util/moderation/PostHider.tsx8
-rw-r--r--src/view/com/util/post-ctrls/PostCtrls.tsx9
-rw-r--r--src/view/com/util/post-ctrls/RepostButton.tsx7
-rw-r--r--src/view/com/util/post-embeds/QuoteEmbed.tsx5
-rw-r--r--src/view/screens/AppPasswords.tsx4
-rw-r--r--src/view/screens/Debug.tsx7
-rw-r--r--src/view/screens/Feeds.tsx2
-rw-r--r--src/view/screens/Lists.tsx2
-rw-r--r--src/view/screens/Log.tsx4
-rw-r--r--src/view/screens/PostThread.tsx4
-rw-r--r--src/view/screens/PreferencesExternalEmbeds.tsx2
-rw-r--r--src/view/screens/PreferencesHomeFeed.tsx11
-rw-r--r--src/view/screens/PreferencesThreads.tsx2
-rw-r--r--src/view/screens/Profile.tsx7
-rw-r--r--src/view/screens/ProfileFeed.tsx61
-rw-r--r--src/view/screens/ProfileList.tsx95
-rw-r--r--src/view/screens/SavedFeeds.tsx15
-rw-r--r--src/view/screens/Search/Search.tsx4
-rw-r--r--src/view/screens/Settings.tsx60
-rw-r--r--src/view/screens/Support.tsx4
-rw-r--r--src/view/shell/Drawer.tsx6
-rw-r--r--src/view/shell/desktop/LeftNav.tsx2
-rw-r--r--src/view/shell/desktop/RightNav.tsx2
-rw-r--r--src/view/shell/desktop/Search.tsx2
-rw-r--r--src/view/shell/index.web.tsx2
108 files changed, 925 insertions, 558 deletions
diff --git a/src/App.native.tsx b/src/App.native.tsx
index 6402b4a89..9de901767 100644
--- a/src/App.native.tsx
+++ b/src/App.native.tsx
@@ -39,6 +39,8 @@ import {
 import {Provider as UnreadNotifsProvider} from 'state/queries/notifications/unread'
 import * as persisted from '#/state/persisted'
 import {Splash} from '#/Splash'
+import {msg} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
 
 SplashScreen.preventAutoHideAsync()
 
@@ -46,17 +48,18 @@ function InnerApp() {
   const colorMode = useColorMode()
   const {isInitialLoad, currentAccount} = useSession()
   const {resumeSession} = useSessionApi()
+  const {_} = useLingui()
 
   // init
   useEffect(() => {
     notifications.init(queryClient)
     listenSessionDropped(() => {
-      Toast.show('Sorry! Your session expired. Please log in again.')
+      Toast.show(_(msg`Sorry! Your session expired. Please log in again.`))
     })
 
     const account = persisted.get('session').currentAccount
     resumeSession(account)
-  }, [resumeSession])
+  }, [resumeSession, _])
 
   return (
     <SafeAreaProvider initialMetrics={initialWindowMetrics}>
diff --git a/src/Navigation.tsx b/src/Navigation.tsx
index 76a893c68..c68cb0580 100644
--- a/src/Navigation.tsx
+++ b/src/Navigation.tsx
@@ -76,6 +76,8 @@ import {PreferencesHomeFeed} from 'view/screens/PreferencesHomeFeed'
 import {PreferencesThreads} from 'view/screens/PreferencesThreads'
 import {PreferencesExternalEmbeds} from '#/view/screens/PreferencesExternalEmbeds'
 import {createNativeStackNavigatorWithAuth} from './view/shell/createNativeStackNavigatorWithAuth'
+import {msg} from '@lingui/macro'
+import {i18n, MessageDescriptor} from '@lingui/core'
 
 const navigationRef = createNavigationContainerRef<AllNavigatorParams>()
 
@@ -93,55 +95,56 @@ const Tab = createBottomTabNavigator<BottomTabNavigatorParams>()
  * These "common screens" are reused across stacks.
  */
 function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) {
-  const title = (page: string) => bskyTitle(page, unreadCountLabel)
+  const title = (page: MessageDescriptor) =>
+    bskyTitle(i18n._(page), unreadCountLabel)
 
   return (
     <>
       <Stack.Screen
         name="NotFound"
         getComponent={() => NotFoundScreen}
-        options={{title: title('Not Found')}}
+        options={{title: title(msg`Not Found`)}}
       />
       <Stack.Screen
         name="Lists"
         component={ListsScreen}
-        options={{title: title('Lists'), requireAuth: true}}
+        options={{title: title(msg`Lists`), requireAuth: true}}
       />
       <Stack.Screen
         name="Moderation"
         getComponent={() => ModerationScreen}
-        options={{title: title('Moderation'), requireAuth: true}}
+        options={{title: title(msg`Moderation`), requireAuth: true}}
       />
       <Stack.Screen
         name="ModerationModlists"
         getComponent={() => ModerationModlistsScreen}
-        options={{title: title('Moderation Lists'), requireAuth: true}}
+        options={{title: title(msg`Moderation Lists`), requireAuth: true}}
       />
       <Stack.Screen
         name="ModerationMutedAccounts"
         getComponent={() => ModerationMutedAccounts}
-        options={{title: title('Muted Accounts'), requireAuth: true}}
+        options={{title: title(msg`Muted Accounts`), requireAuth: true}}
       />
       <Stack.Screen
         name="ModerationBlockedAccounts"
         getComponent={() => ModerationBlockedAccounts}
-        options={{title: title('Blocked Accounts'), requireAuth: true}}
+        options={{title: title(msg`Blocked Accounts`), requireAuth: true}}
       />
       <Stack.Screen
         name="Settings"
         getComponent={() => SettingsScreen}
-        options={{title: title('Settings'), requireAuth: true}}
+        options={{title: title(msg`Settings`), requireAuth: true}}
       />
       <Stack.Screen
         name="LanguageSettings"
         getComponent={() => LanguageSettingsScreen}
-        options={{title: title('Language Settings'), requireAuth: true}}
+        options={{title: title(msg`Language Settings`), requireAuth: true}}
       />
       <Stack.Screen
         name="Profile"
         getComponent={() => ProfileScreen}
         options={({route}) => ({
-          title: title(`@${route.params.name}`),
+          title: title(msg`@${route.params.name}`),
           animation: 'none',
         })}
       />
@@ -149,106 +152,112 @@ function commonScreens(Stack: typeof HomeTab, unreadCountLabel?: string) {
         name="ProfileFollowers"
         getComponent={() => ProfileFollowersScreen}
         options={({route}) => ({
-          title: title(`People following @${route.params.name}`),
+          title: title(msg`People following @${route.params.name}`),
         })}
       />
       <Stack.Screen
         name="ProfileFollows"
         getComponent={() => ProfileFollowsScreen}
         options={({route}) => ({
-          title: title(`People followed by @${route.params.name}`),
+          title: title(msg`People followed by @${route.params.name}`),
         })}
       />
       <Stack.Screen
         name="ProfileList"
         getComponent={() => ProfileListScreen}
-        options={{title: title('List'), requireAuth: true}}
+        options={{title: title(msg`List`), requireAuth: true}}
       />
       <Stack.Screen
         name="PostThread"
         getComponent={() => PostThreadScreen}
-        options={({route}) => ({title: title(`Post by @${route.params.name}`)})}
+        options={({route}) => ({
+          title: title(msg`Post by @${route.params.name}`),
+        })}
       />
       <Stack.Screen
         name="PostLikedBy"
         getComponent={() => PostLikedByScreen}
-        options={({route}) => ({title: title(`Post by @${route.params.name}`)})}
+        options={({route}) => ({
+          title: title(msg`Post by @${route.params.name}`),
+        })}
       />
       <Stack.Screen
         name="PostRepostedBy"
         getComponent={() => PostRepostedByScreen}
-        options={({route}) => ({title: title(`Post by @${route.params.name}`)})}
+        options={({route}) => ({
+          title: title(msg`Post by @${route.params.name}`),
+        })}
       />
       <Stack.Screen
         name="ProfileFeed"
         getComponent={() => ProfileFeedScreen}
-        options={{title: title('Feed'), requireAuth: true}}
+        options={{title: title(msg`Feed`), requireAuth: true}}
       />
       <Stack.Screen
         name="ProfileFeedLikedBy"
         getComponent={() => ProfileFeedLikedByScreen}
-        options={{title: title('Liked by')}}
+        options={{title: title(msg`Liked by`)}}
       />
       <Stack.Screen
         name="Debug"
         getComponent={() => DebugScreen}
-        options={{title: title('Debug'), requireAuth: true}}
+        options={{title: title(msg`Debug`), requireAuth: true}}
       />
       <Stack.Screen
         name="Log"
         getComponent={() => LogScreen}
-        options={{title: title('Log'), requireAuth: true}}
+        options={{title: title(msg`Log`), requireAuth: true}}
       />
       <Stack.Screen
         name="Support"
         getComponent={() => SupportScreen}
-        options={{title: title('Support')}}
+        options={{title: title(msg`Support`)}}
       />
       <Stack.Screen
         name="PrivacyPolicy"
         getComponent={() => PrivacyPolicyScreen}
-        options={{title: title('Privacy Policy')}}
+        options={{title: title(msg`Privacy Policy`)}}
       />
       <Stack.Screen
         name="TermsOfService"
         getComponent={() => TermsOfServiceScreen}
-        options={{title: title('Terms of Service')}}
+        options={{title: title(msg`Terms of Service`)}}
       />
       <Stack.Screen
         name="CommunityGuidelines"
         getComponent={() => CommunityGuidelinesScreen}
-        options={{title: title('Community Guidelines')}}
+        options={{title: title(msg`Community Guidelines`)}}
       />
       <Stack.Screen
         name="CopyrightPolicy"
         getComponent={() => CopyrightPolicyScreen}
-        options={{title: title('Copyright Policy')}}
+        options={{title: title(msg`Copyright Policy`)}}
       />
       <Stack.Screen
         name="AppPasswords"
         getComponent={() => AppPasswords}
-        options={{title: title('App Passwords'), requireAuth: true}}
+        options={{title: title(msg`App Passwords`), requireAuth: true}}
       />
       <Stack.Screen
         name="SavedFeeds"
         getComponent={() => SavedFeeds}
-        options={{title: title('Edit My Feeds'), requireAuth: true}}
+        options={{title: title(msg`Edit My Feeds`), requireAuth: true}}
       />
       <Stack.Screen
         name="PreferencesHomeFeed"
         getComponent={() => PreferencesHomeFeed}
-        options={{title: title('Home Feed Preferences'), requireAuth: true}}
+        options={{title: title(msg`Home Feed Preferences`), requireAuth: true}}
       />
       <Stack.Screen
         name="PreferencesThreads"
         getComponent={() => PreferencesThreads}
-        options={{title: title('Threads Preferences'), requireAuth: true}}
+        options={{title: title(msg`Threads Preferences`), requireAuth: true}}
       />
       <Stack.Screen
         name="PreferencesExternalEmbeds"
         getComponent={() => PreferencesExternalEmbeds}
         options={{
-          title: title('External Media Preferences'),
+          title: title(msg`External Media Preferences`),
           requireAuth: true,
         }}
       />
@@ -407,7 +416,7 @@ const FlatNavigator = () => {
   const pal = usePalette('default')
   const numUnread = useUnreadNotifications()
 
-  const title = (page: string) => bskyTitle(page, numUnread)
+  const title = (page: MessageDescriptor) => bskyTitle(i18n._(page), numUnread)
   return (
     <Flat.Navigator
       screenOptions={{
@@ -420,22 +429,22 @@ const FlatNavigator = () => {
       <Flat.Screen
         name="Home"
         getComponent={() => HomeScreen}
-        options={{title: title('Home'), requireAuth: true}}
+        options={{title: title(msg`Home`), requireAuth: true}}
       />
       <Flat.Screen
         name="Search"
         getComponent={() => SearchScreen}
-        options={{title: title('Search')}}
+        options={{title: title(msg`Search`)}}
       />
       <Flat.Screen
         name="Feeds"
         getComponent={() => FeedsScreen}
-        options={{title: title('Feeds'), requireAuth: true}}
+        options={{title: title(msg`Feeds`), requireAuth: true}}
       />
       <Flat.Screen
         name="Notifications"
         getComponent={() => NotificationsScreen}
-        options={{title: title('Notifications'), requireAuth: true}}
+        options={{title: title(msg`Notifications`), requireAuth: true}}
       />
       {commonScreens(Flat as typeof HomeTab, numUnread)}
     </Flat.Navigator>
diff --git a/src/view/com/auth/LoggedOut.tsx b/src/view/com/auth/LoggedOut.tsx
index c0427ff54..603abbab2 100644
--- a/src/view/com/auth/LoggedOut.tsx
+++ b/src/view/com/auth/LoggedOut.tsx
@@ -2,7 +2,7 @@ import React from 'react'
 import {View, Pressable} from 'react-native'
 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
 import {useLingui} from '@lingui/react'
-import {msg} from '@lingui/macro'
+import {Trans, msg} from '@lingui/macro'
 import {useNavigation} from '@react-navigation/native'
 
 import {isIOS, isNative} from 'platform/detection'
@@ -119,7 +119,7 @@ export function LoggedOut({onDismiss}: {onDismiss?: () => void}) {
             }}
             onPress={onPressSearch}>
             <Text type="lg-bold" style={[pal.text]}>
-              Search{' '}
+              <Trans>Search</Trans>{' '}
             </Text>
             <FontAwesomeIcon
               icon="search"
diff --git a/src/view/com/auth/SplashScreen.web.tsx b/src/view/com/auth/SplashScreen.web.tsx
index 1cc7b9146..d2b1a47e3 100644
--- a/src/view/com/auth/SplashScreen.web.tsx
+++ b/src/view/com/auth/SplashScreen.web.tsx
@@ -74,7 +74,7 @@ export const SplashScreen = ({
                 // TODO: web accessibility
                 accessibilityRole="button">
                 <Text style={[s.white, styles.btnLabel]}>
-                  Create a new account
+                  <Trans>Create a new account</Trans>
                 </Text>
               </TouchableOpacity>
               <TouchableOpacity
diff --git a/src/view/com/auth/create/Step1.tsx b/src/view/com/auth/create/Step1.tsx
index c9d19e868..0f8581c0b 100644
--- a/src/view/com/auth/create/Step1.tsx
+++ b/src/view/com/auth/create/Step1.tsx
@@ -77,7 +77,7 @@ export function Step1({
             value={uiState.serviceUrl}
             editable
             onChange={onChangeServiceUrl}
-            accessibilityHint="Input hosting provider address"
+            accessibilityHint={_(msg`Input hosting provider address`)}
             accessibilityLabel={_(msg`Hosting provider address`)}
             accessibilityLabelledBy="addressProvider"
           />
@@ -125,6 +125,7 @@ function Option({
 }>) {
   const theme = useTheme()
   const pal = usePalette('default')
+  const {_} = useLingui()
   const circleFillStyle = React.useMemo(
     () => ({
       backgroundColor: theme.palette.primary.background,
@@ -139,7 +140,7 @@ function Option({
         testID={testID}
         accessibilityRole="button"
         accessibilityLabel={label}
-        accessibilityHint={`Sets hosting provider to ${label}`}>
+        accessibilityHint={_(msg`Sets hosting provider to ${label}`)}>
         <View style={styles.optionHeading}>
           <View style={[styles.circle, pal.border]}>
             {isSelected ? (
diff --git a/src/view/com/auth/create/Step2.tsx b/src/view/com/auth/create/Step2.tsx
index 8b143ff37..53e1e02c9 100644
--- a/src/view/com/auth/create/Step2.tsx
+++ b/src/view/com/auth/create/Step2.tsx
@@ -60,7 +60,7 @@ export function Step2({
       {uiState.isInviteCodeRequired && (
         <View style={s.pb20}>
           <Text type="md-medium" style={[pal.text, s.mb2]}>
-            Invite code
+            <Trans>Invite code</Trans>
           </Text>
           <TextInput
             testID="inviteCodeInput"
@@ -70,7 +70,7 @@ export function Step2({
             editable
             onChange={value => uiDispatch({type: 'set-invite-code', value})}
             accessibilityLabel={_(msg`Invite code`)}
-            accessibilityHint="Input invite code to proceed"
+            accessibilityHint={_(msg`Input invite code to proceed`)}
             autoCapitalize="none"
             autoComplete="off"
             autoCorrect={false}
@@ -80,7 +80,7 @@ export function Step2({
 
       {!uiState.inviteCode && uiState.isInviteCodeRequired ? (
         <Text style={[s.alignBaseline, pal.text]}>
-          Don't have an invite code?{' '}
+          <Trans>Don't have an invite code?</Trans>{' '}
           <TouchableWithoutFeedback
             onPress={onPressWaitlist}
             accessibilityLabel={_(msg`Join the waitlist.`)}
@@ -106,7 +106,7 @@ export function Step2({
               editable
               onChange={value => uiDispatch({type: 'set-email', value})}
               accessibilityLabel={_(msg`Email`)}
-              accessibilityHint="Input email for Bluesky waitlist"
+              accessibilityHint={_(msg`Input email for Bluesky waitlist`)}
               accessibilityLabelledBy="email"
               autoCapitalize="none"
               autoComplete="off"
@@ -130,7 +130,7 @@ export function Step2({
               secureTextEntry
               onChange={value => uiDispatch({type: 'set-password', value})}
               accessibilityLabel={_(msg`Password`)}
-              accessibilityHint="Set password"
+              accessibilityHint={_(msg`Set password`)}
               accessibilityLabelledBy="password"
               autoCapitalize="none"
               autoComplete="off"
@@ -154,7 +154,7 @@ export function Step2({
               buttonStyle={[pal.border, styles.dateInputButton]}
               buttonLabelType="lg"
               accessibilityLabel={_(msg`Birthday`)}
-              accessibilityHint="Enter your birth date"
+              accessibilityHint={_(msg`Enter your birth date`)}
               accessibilityLabelledBy="birthDate"
             />
           </View>
diff --git a/src/view/com/auth/create/Step3.tsx b/src/view/com/auth/create/Step3.tsx
index 4c8a58519..2b2b9f7fe 100644
--- a/src/view/com/auth/create/Step3.tsx
+++ b/src/view/com/auth/create/Step3.tsx
@@ -36,7 +36,7 @@ export function Step3({
           onChange={value => uiDispatch({type: 'set-handle', value})}
           // TODO: Add explicit text label
           accessibilityLabel={_(msg`User handle`)}
-          accessibilityHint="Input your user handle"
+          accessibilityHint={_(msg`Input your user handle`)}
         />
         <Text type="lg" style={[pal.text, s.pl5, s.pt10]}>
           <Trans>Your full handle will be</Trans>{' '}
diff --git a/src/view/com/auth/create/StepHeader.tsx b/src/view/com/auth/create/StepHeader.tsx
index 4b4eb5d23..41f912051 100644
--- a/src/view/com/auth/create/StepHeader.tsx
+++ b/src/view/com/auth/create/StepHeader.tsx
@@ -2,13 +2,18 @@ import React from 'react'
 import {StyleSheet, View} from 'react-native'
 import {Text} from 'view/com/util/text/Text'
 import {usePalette} from 'lib/hooks/usePalette'
+import {Trans} from '@lingui/macro'
 
 export function StepHeader({step, title}: {step: string; title: string}) {
   const pal = usePalette('default')
   return (
     <View style={styles.container}>
       <Text type="lg" style={[pal.textLight]}>
-        {step === '3' ? 'Last step!' : <>Step {step} of 3</>}
+        {step === '3' ? (
+          <Trans>Last step!</Trans>
+        ) : (
+          <Trans>Step {step} of 3</Trans>
+        )}
       </Text>
       <Text style={[pal.text]} type="title-xl">
         {title}
diff --git a/src/view/com/auth/login/ChooseAccountForm.tsx b/src/view/com/auth/login/ChooseAccountForm.tsx
index 73ddfc9d6..32cd8315d 100644
--- a/src/view/com/auth/login/ChooseAccountForm.tsx
+++ b/src/view/com/auth/login/ChooseAccountForm.tsx
@@ -42,7 +42,7 @@ function AccountItem({
       onPress={onPress}
       accessibilityRole="button"
       accessibilityLabel={_(msg`Sign in as ${account.handle}`)}
-      accessibilityHint="Double tap to sign in">
+      accessibilityHint={_(msg`Double tap to sign in`)}>
       <View style={[pal.borderDark, styles.groupContent, styles.noTopBorder]}>
         <View style={s.p10}>
           <UserAvatar avatar={profile?.avatar} size={30} />
@@ -95,19 +95,19 @@ export const ChooseAccountForm = ({
       if (account.accessJwt) {
         if (account.did === currentAccount?.did) {
           setShowLoggedOut(false)
-          Toast.show(`Already signed in as @${account.handle}`)
+          Toast.show(_(msg`Already signed in as @${account.handle}`))
         } else {
           await initSession(account)
           track('Sign In', {resumedSession: true})
           setTimeout(() => {
-            Toast.show(`Signed in as @${account.handle}`)
+            Toast.show(_(msg`Signed in as @${account.handle}`))
           }, 100)
         }
       } else {
         onSelectAccount(account)
       }
     },
-    [currentAccount, track, initSession, onSelectAccount, setShowLoggedOut],
+    [currentAccount, track, initSession, onSelectAccount, setShowLoggedOut, _],
   )
 
   return (
diff --git a/src/view/com/auth/login/ForgotPasswordForm.tsx b/src/view/com/auth/login/ForgotPasswordForm.tsx
index 215c393d9..f9bb64f98 100644
--- a/src/view/com/auth/login/ForgotPasswordForm.tsx
+++ b/src/view/com/auth/login/ForgotPasswordForm.tsx
@@ -67,7 +67,7 @@ export const ForgotPasswordForm = ({
 
   const onPressNext = async () => {
     if (!EmailValidator.validate(email)) {
-      return setError('Your email appears to be invalid.')
+      return setError(_(msg`Your email appears to be invalid.`))
     }
 
     setError('')
@@ -83,7 +83,9 @@ export const ForgotPasswordForm = ({
       setIsProcessing(false)
       if (isNetworkError(e)) {
         setError(
-          'Unable to contact your service. Please check your Internet connection.',
+          _(
+            msg`Unable to contact your service. Please check your Internet connection.`,
+          ),
         )
       } else {
         setError(cleanError(errMsg))
@@ -112,7 +114,9 @@ export const ForgotPasswordForm = ({
             onPress={onPressSelectService}
             accessibilityRole="button"
             accessibilityLabel={_(msg`Hosting provider`)}
-            accessibilityHint="Sets hosting provider for password reset">
+            accessibilityHint={_(
+              msg`Sets hosting provider for password reset`,
+            )}>
             <FontAwesomeIcon
               icon="globe"
               style={[pal.textLight, styles.groupContentIcon]}
@@ -136,7 +140,7 @@ export const ForgotPasswordForm = ({
             <TextInput
               testID="forgotPasswordEmail"
               style={[pal.text, styles.textInput]}
-              placeholder="Email address"
+              placeholder={_(msg`Email address`)}
               placeholderTextColor={pal.colors.textLight}
               autoCapitalize="none"
               autoFocus
@@ -146,7 +150,7 @@ export const ForgotPasswordForm = ({
               onChangeText={setEmail}
               editable={!isProcessing}
               accessibilityLabel={_(msg`Email`)}
-              accessibilityHint="Sets email for password reset"
+              accessibilityHint={_(msg`Sets email for password reset`)}
             />
           </View>
         </View>
@@ -179,7 +183,7 @@ export const ForgotPasswordForm = ({
               onPress={onPressNext}
               accessibilityRole="button"
               accessibilityLabel={_(msg`Go to next`)}
-              accessibilityHint="Navigates to the next screen">
+              accessibilityHint={_(msg`Navigates to the next screen`)}>
               <Text type="xl-bold" style={[pal.link, s.pr5]}>
                 <Trans>Next</Trans>
               </Text>
diff --git a/src/view/com/auth/login/LoginForm.tsx b/src/view/com/auth/login/LoginForm.tsx
index 98c5eb374..10608a54b 100644
--- a/src/view/com/auth/login/LoginForm.tsx
+++ b/src/view/com/auth/login/LoginForm.tsx
@@ -145,7 +145,7 @@ export const LoginForm = ({
             onPress={onPressSelectService}
             accessibilityRole="button"
             accessibilityLabel={_(msg`Select service`)}
-            accessibilityHint="Sets server for the Bluesky client">
+            accessibilityHint={_(msg`Sets server for the Bluesky client`)}>
             <Text type="xl" style={[pal.text, styles.textBtnLabel]}>
               {toNiceDomain(serviceUrl)}
             </Text>
@@ -190,7 +190,9 @@ export const LoginForm = ({
             }
             editable={!isProcessing}
             accessibilityLabel={_(msg`Username or email address`)}
-            accessibilityHint="Input the username or email address you used at signup"
+            accessibilityHint={_(
+              msg`Input the username or email address you used at signup`,
+            )}
           />
         </View>
         <View style={[pal.borderDark, styles.groupContent]}>
@@ -221,8 +223,8 @@ export const LoginForm = ({
             accessibilityLabel={_(msg`Password`)}
             accessibilityHint={
               identifier === ''
-                ? 'Input your password'
-                : `Input the password tied to ${identifier}`
+                ? _(msg`Input your password`)
+                : _(msg`Input the password tied to ${identifier}`)
             }
           />
           <TouchableOpacity
@@ -231,7 +233,7 @@ export const LoginForm = ({
             onPress={onPressForgotPassword}
             accessibilityRole="button"
             accessibilityLabel={_(msg`Forgot password`)}
-            accessibilityHint="Opens password reset form">
+            accessibilityHint={_(msg`Opens password reset form`)}>
             <Text style={pal.link}>
               <Trans>Forgot</Trans>
             </Text>
@@ -261,7 +263,7 @@ export const LoginForm = ({
             onPress={onPressRetryConnect}
             accessibilityRole="button"
             accessibilityLabel={_(msg`Retry`)}
-            accessibilityHint="Retries login">
+            accessibilityHint={_(msg`Retries login`)}>
             <Text type="xl-bold" style={[pal.link, s.pr5]}>
               <Trans>Retry</Trans>
             </Text>
@@ -281,7 +283,7 @@ export const LoginForm = ({
             onPress={onPressNext}
             accessibilityRole="button"
             accessibilityLabel={_(msg`Go to next`)}
-            accessibilityHint="Navigates to the next screen">
+            accessibilityHint={_(msg`Navigates to the next screen`)}>
             <Text type="xl-bold" style={[pal.link, s.pr5]}>
               <Trans>Next</Trans>
             </Text>
diff --git a/src/view/com/auth/login/PasswordUpdatedForm.tsx b/src/view/com/auth/login/PasswordUpdatedForm.tsx
index 1e07588a9..71f750b14 100644
--- a/src/view/com/auth/login/PasswordUpdatedForm.tsx
+++ b/src/view/com/auth/login/PasswordUpdatedForm.tsx
@@ -36,7 +36,7 @@ export const PasswordUpdatedForm = ({
             onPress={onPressNext}
             accessibilityRole="button"
             accessibilityLabel={_(msg`Close alert`)}
-            accessibilityHint="Closes password update alert">
+            accessibilityHint={_(msg`Closes password update alert`)}>
             <Text type="xl-bold" style={[pal.link, s.pr5]}>
               <Trans>Okay</Trans>
             </Text>
diff --git a/src/view/com/auth/login/SetNewPasswordForm.tsx b/src/view/com/auth/login/SetNewPasswordForm.tsx
index 2bb614df2..630c6afde 100644
--- a/src/view/com/auth/login/SetNewPasswordForm.tsx
+++ b/src/view/com/auth/login/SetNewPasswordForm.tsx
@@ -95,7 +95,7 @@ export const SetNewPasswordForm = ({
             <TextInput
               testID="resetCodeInput"
               style={[pal.text, styles.textInput]}
-              placeholder="Reset code"
+              placeholder={_(msg`Reset code`)}
               placeholderTextColor={pal.colors.textLight}
               autoCapitalize="none"
               autoCorrect={false}
@@ -106,7 +106,9 @@ export const SetNewPasswordForm = ({
               editable={!isProcessing}
               accessible={true}
               accessibilityLabel={_(msg`Reset code`)}
-              accessibilityHint="Input code sent to your email for password reset"
+              accessibilityHint={_(
+                msg`Input code sent to your email for password reset`,
+              )}
             />
           </View>
           <View style={[pal.borderDark, styles.groupContent]}>
@@ -117,7 +119,7 @@ export const SetNewPasswordForm = ({
             <TextInput
               testID="newPasswordInput"
               style={[pal.text, styles.textInput]}
-              placeholder="New password"
+              placeholder={_(msg`New password`)}
               placeholderTextColor={pal.colors.textLight}
               autoCapitalize="none"
               autoCorrect={false}
@@ -128,7 +130,7 @@ export const SetNewPasswordForm = ({
               editable={!isProcessing}
               accessible={true}
               accessibilityLabel={_(msg`Password`)}
-              accessibilityHint="Input new password"
+              accessibilityHint={_(msg`Input new password`)}
             />
           </View>
         </View>
@@ -161,7 +163,7 @@ export const SetNewPasswordForm = ({
               onPress={onPressNext}
               accessibilityRole="button"
               accessibilityLabel={_(msg`Go to next`)}
-              accessibilityHint="Navigates to the next screen">
+              accessibilityHint={_(msg`Navigates to the next screen`)}>
               <Text type="xl-bold" style={[pal.link, s.pr5]}>
                 <Trans>Next</Trans>
               </Text>
diff --git a/src/view/com/auth/onboarding/RecommendedFeedsItem.tsx b/src/view/com/auth/onboarding/RecommendedFeedsItem.tsx
index fcc4572af..63fb0ec15 100644
--- a/src/view/com/auth/onboarding/RecommendedFeedsItem.tsx
+++ b/src/view/com/auth/onboarding/RecommendedFeedsItem.tsx
@@ -18,6 +18,8 @@ import {
 } from '#/state/queries/preferences'
 import {logger} from '#/logger'
 import {useAnalytics} from '#/lib/analytics/analytics'
+import {Trans, msg} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
 
 export function RecommendedFeedsItem({
   item,
@@ -26,6 +28,7 @@ export function RecommendedFeedsItem({
 }) {
   const {isMobile} = useWebMediaQueries()
   const pal = usePalette('default')
+  const {_} = useLingui()
   const {data: preferences} = usePreferencesQuery()
   const {
     mutateAsync: pinFeed,
@@ -51,7 +54,7 @@ export function RecommendedFeedsItem({
         await removeFeed({uri: item.uri})
         resetRemoveFeed()
       } catch (e) {
-        Toast.show('There was an issue contacting your server')
+        Toast.show(_(msg`There was an issue contacting your server`))
         logger.error('Failed to unsave feed', {error: e})
       }
     } else {
@@ -60,7 +63,7 @@ export function RecommendedFeedsItem({
         resetPinFeed()
         track('Onboarding:CustomFeedAdded')
       } catch (e) {
-        Toast.show('There was an issue contacting your server')
+        Toast.show(_(msg`There was an issue contacting your server`))
         logger.error('Failed to pin feed', {error: e})
       }
     }
@@ -94,7 +97,7 @@ export function RecommendedFeedsItem({
           </Text>
 
           <Text style={[pal.textLight, {marginBottom: 8}]} numberOfLines={1}>
-            by {sanitizeHandle(item.creator.handle, '@')}
+            <Trans>by {sanitizeHandle(item.creator.handle, '@')}</Trans>
           </Text>
 
           {item.description ? (
@@ -133,7 +136,7 @@ export function RecommendedFeedsItem({
                       color={pal.colors.textInverted}
                     />
                     <Text type="lg-medium" style={pal.textInverted}>
-                      Added
+                      <Trans>Added</Trans>
                     </Text>
                   </>
                 ) : (
@@ -144,7 +147,7 @@ export function RecommendedFeedsItem({
                       color={pal.colors.textInverted}
                     />
                     <Text type="lg-medium" style={pal.textInverted}>
-                      Add
+                      <Trans>Add</Trans>
                     </Text>
                   </>
                 )}
diff --git a/src/view/com/auth/onboarding/RecommendedFollows.tsx b/src/view/com/auth/onboarding/RecommendedFollows.tsx
index 372bbec6a..93cfb7386 100644
--- a/src/view/com/auth/onboarding/RecommendedFollows.tsx
+++ b/src/view/com/auth/onboarding/RecommendedFollows.tsx
@@ -83,7 +83,7 @@ export function RecommendedFollows({next}: Props) {
             <Text
               type="2xl-medium"
               style={{color: '#fff', position: 'relative', top: -1}}>
-              <Trans>Done</Trans>
+              <Trans context="action">Done</Trans>
             </Text>
             <FontAwesomeIcon icon="angle-right" color="#fff" size={14} />
           </View>
diff --git a/src/view/com/auth/onboarding/WelcomeDesktop.tsx b/src/view/com/auth/onboarding/WelcomeDesktop.tsx
index 1a30c17f9..fdb31197c 100644
--- a/src/view/com/auth/onboarding/WelcomeDesktop.tsx
+++ b/src/view/com/auth/onboarding/WelcomeDesktop.tsx
@@ -7,6 +7,7 @@ import {usePalette} from 'lib/hooks/usePalette'
 import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
 import {TitleColumnLayout} from 'view/com/util/layouts/TitleColumnLayout'
 import {Button} from 'view/com/util/forms/Button'
+import {Trans} from '@lingui/macro'
 
 type Props = {
   next: () => void
@@ -17,7 +18,7 @@ export function WelcomeDesktop({next}: Props) {
   const pal = usePalette('default')
   const horizontal = useMediaQuery({minWidth: 1300})
   const title = (
-    <>
+    <Trans>
       <Text
         style={[
           pal.textLight,
@@ -40,7 +41,7 @@ export function WelcomeDesktop({next}: Props) {
         ]}>
         Bluesky
       </Text>
-    </>
+    </Trans>
   )
   return (
     <TitleColumnLayout
@@ -52,10 +53,12 @@ export function WelcomeDesktop({next}: Props) {
         <FontAwesomeIcon icon={'globe'} size={36} color={pal.colors.link} />
         <View style={[styles.rowText]}>
           <Text type="xl-bold" style={[pal.text]}>
-            Bluesky is public.
+            <Trans>Bluesky is public.</Trans>
           </Text>
           <Text type="xl" style={[pal.text, s.pt2]}>
-            Your posts, likes, and blocks are public. Mutes are private.
+            <Trans>
+              Your posts, likes, and blocks are public. Mutes are private.
+            </Trans>
           </Text>
         </View>
       </View>
@@ -63,10 +66,10 @@ export function WelcomeDesktop({next}: Props) {
         <FontAwesomeIcon icon={'at'} size={36} color={pal.colors.link} />
         <View style={[styles.rowText]}>
           <Text type="xl-bold" style={[pal.text]}>
-            Bluesky is open.
+            <Trans>Bluesky is open.</Trans>
           </Text>
           <Text type="xl" style={[pal.text, s.pt2]}>
-            Never lose access to your followers and data.
+            <Trans>Never lose access to your followers and data.</Trans>
           </Text>
         </View>
       </View>
@@ -74,10 +77,13 @@ export function WelcomeDesktop({next}: Props) {
         <FontAwesomeIcon icon={'gear'} size={36} color={pal.colors.link} />
         <View style={[styles.rowText]}>
           <Text type="xl-bold" style={[pal.text]}>
-            Bluesky is flexible.
+            <Trans>Bluesky is flexible.</Trans>
           </Text>
           <Text type="xl" style={[pal.text, s.pt2]}>
-            Choose the algorithms that power your experience with custom feeds.
+            <Trans>
+              Choose the algorithms that power your experience with custom
+              feeds.
+            </Trans>
           </Text>
         </View>
       </View>
@@ -94,7 +100,7 @@ export function WelcomeDesktop({next}: Props) {
             <Text
               type="2xl-medium"
               style={{color: '#fff', position: 'relative', top: -1}}>
-              Next
+              <Trans context="action">Next</Trans>
             </Text>
             <FontAwesomeIcon icon="angle-right" color="#fff" size={14} />
           </View>
diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx
index a834cfc0e..e24fdcf3e 100644
--- a/src/view/com/composer/Composer.tsx
+++ b/src/view/com/composer/Composer.tsx
@@ -260,7 +260,11 @@ export const ComposePost = observer(function ComposePost({
     setLangPrefs.savePostLanguageToHistory()
     onPost?.()
     onClose()
-    Toast.show(`Your ${replyTo ? 'reply' : 'post'} has been published`)
+    Toast.show(
+      replyTo
+        ? _(msg`Your reply has been published`)
+        : _(msg`Your post has been published`),
+    )
   }
 
   const canPost = useMemo(
@@ -269,7 +273,9 @@ export const ComposePost = observer(function ComposePost({
       (!requireAltTextEnabled || !gallery.needsAltText),
     [graphemeLength, requireAltTextEnabled, gallery.needsAltText],
   )
-  const selectTextInputPlaceholder = replyTo ? 'Write your reply' : `What's up?`
+  const selectTextInputPlaceholder = replyTo
+    ? _(msg`Write your reply`)
+    : _(msg`What's up?`)
 
   const canSelectImages = useMemo(() => gallery.size < 4, [gallery.size])
   const hasMedia = gallery.size > 0 || Boolean(extLink)
@@ -291,7 +297,9 @@ export const ComposePost = observer(function ComposePost({
             onAccessibilityEscape={onPressCancel}
             accessibilityRole="button"
             accessibilityLabel={_(msg`Cancel`)}
-            accessibilityHint="Closes post composer and discards post draft">
+            accessibilityHint={_(
+              msg`Closes post composer and discards post draft`,
+            )}>
             <Text style={[pal.link, s.f18]}>
               <Trans>Cancel</Trans>
             </Text>
@@ -323,7 +331,7 @@ export const ComposePost = observer(function ComposePost({
                   onPress={onPressPublish}
                   accessibilityRole="button"
                   accessibilityLabel={
-                    replyTo ? 'Publish reply' : 'Publish post'
+                    replyTo ? _(msg`Publish reply`) : _(msg`Publish post`)
                   }
                   accessibilityHint="">
                   <LinearGradient
@@ -335,14 +343,18 @@ export const ComposePost = observer(function ComposePost({
                     end={{x: 1, y: 1}}
                     style={styles.postBtn}>
                     <Text style={[s.white, s.f16, s.bold]}>
-                      {replyTo ? 'Reply' : 'Post'}
+                      {replyTo ? (
+                        <Trans context="action">Reply</Trans>
+                      ) : (
+                        <Trans context="action">Post</Trans>
+                      )}
                     </Text>
                   </LinearGradient>
                 </TouchableOpacity>
               ) : (
                 <View style={[styles.postBtn, pal.btn]}>
                   <Text style={[pal.textLight, s.f16, s.bold]}>
-                    <Trans>Post</Trans>
+                    <Trans context="action">Post</Trans>
                   </Text>
                 </View>
               )}
@@ -400,7 +412,9 @@ export const ComposePost = observer(function ComposePost({
               onError={setError}
               accessible={true}
               accessibilityLabel={_(msg`Write post`)}
-              accessibilityHint={`Compose posts up to ${MAX_GRAPHEME_LENGTH} characters in length`}
+              accessibilityHint={_(
+                msg`Compose posts up to ${MAX_GRAPHEME_LENGTH} characters in length`,
+              )}
             />
           </View>
 
@@ -429,7 +443,9 @@ export const ComposePost = observer(function ComposePost({
                   onPress={() => onPressAddLinkCard(url)}
                   accessibilityRole="button"
                   accessibilityLabel={_(msg`Add link card`)}
-                  accessibilityHint={`Creates a card with a thumbnail. The card links to ${url}`}>
+                  accessibilityHint={_(
+                    msg`Creates a card with a thumbnail. The card links to ${url}`,
+                  )}>
                   <Text style={pal.text}>
                     <Trans>Add link card:</Trans>{' '}
                     <Text style={[pal.link, s.ml5]}>{toShortUrl(url)}</Text>
diff --git a/src/view/com/composer/ExternalEmbed.tsx b/src/view/com/composer/ExternalEmbed.tsx
index 502e4b4d2..02dd1bbd7 100644
--- a/src/view/com/composer/ExternalEmbed.tsx
+++ b/src/view/com/composer/ExternalEmbed.tsx
@@ -68,7 +68,7 @@ export const ExternalEmbed = ({
         onPress={onRemove}
         accessibilityRole="button"
         accessibilityLabel={_(msg`Remove image preview`)}
-        accessibilityHint={`Removes default thumbnail from ${link.uri}`}
+        accessibilityHint={_(msg`Removes default thumbnail from ${link.uri}`)}
         onAccessibilityEscape={onRemove}>
         <FontAwesomeIcon size={18} icon="xmark" style={s.white} />
       </TouchableOpacity>
diff --git a/src/view/com/composer/Prompt.tsx b/src/view/com/composer/Prompt.tsx
index 9964359ac..632bb2634 100644
--- a/src/view/com/composer/Prompt.tsx
+++ b/src/view/com/composer/Prompt.tsx
@@ -22,7 +22,7 @@ export function ComposePrompt({onPressCompose}: {onPressCompose: () => void}) {
       onPress={() => onPressCompose()}
       accessibilityRole="button"
       accessibilityLabel={_(msg`Compose reply`)}
-      accessibilityHint="Opens composer">
+      accessibilityHint={_(msg`Opens composer`)}>
       <UserAvatar avatar={profile?.avatar} size={38} />
       <Text
         type="xl"
diff --git a/src/view/com/composer/photos/OpenCameraBtn.tsx b/src/view/com/composer/photos/OpenCameraBtn.tsx
index 69f63c55f..a288e7310 100644
--- a/src/view/com/composer/photos/OpenCameraBtn.tsx
+++ b/src/view/com/composer/photos/OpenCameraBtn.tsx
@@ -58,7 +58,7 @@ export function OpenCameraBtn({gallery}: Props) {
       hitSlop={HITSLOP_10}
       accessibilityRole="button"
       accessibilityLabel={_(msg`Camera`)}
-      accessibilityHint="Opens camera on device">
+      accessibilityHint={_(msg`Opens camera on device`)}>
       <FontAwesomeIcon
         icon="camera"
         style={pal.link as FontAwesomeIconStyle}
diff --git a/src/view/com/composer/photos/SelectPhotoBtn.tsx b/src/view/com/composer/photos/SelectPhotoBtn.tsx
index af0a22b01..f7fa9502d 100644
--- a/src/view/com/composer/photos/SelectPhotoBtn.tsx
+++ b/src/view/com/composer/photos/SelectPhotoBtn.tsx
@@ -41,7 +41,7 @@ export function SelectPhotoBtn({gallery}: Props) {
       hitSlop={HITSLOP_10}
       accessibilityRole="button"
       accessibilityLabel={_(msg`Gallery`)}
-      accessibilityHint="Opens device photo gallery">
+      accessibilityHint={_(msg`Opens device photo gallery`)}>
       <FontAwesomeIcon
         icon={['far', 'image']}
         style={pal.link as FontAwesomeIconStyle}
diff --git a/src/view/com/composer/text-input/web/Autocomplete.tsx b/src/view/com/composer/text-input/web/Autocomplete.tsx
index 51197b8e4..76058fed3 100644
--- a/src/view/com/composer/text-input/web/Autocomplete.tsx
+++ b/src/view/com/composer/text-input/web/Autocomplete.tsx
@@ -17,6 +17,7 @@ import {usePalette} from 'lib/hooks/usePalette'
 import {Text} from 'view/com/util/text/Text'
 import {UserAvatar} from 'view/com/util/UserAvatar'
 import {useGrapheme} from '../hooks/useGrapheme'
+import {Trans} from '@lingui/macro'
 
 interface MentionListRef {
   onKeyDown: (props: SuggestionKeyDownProps) => boolean
@@ -187,7 +188,7 @@ const MentionList = forwardRef<MentionListRef, SuggestionProps>(
             })
           ) : (
             <Text type="sm" style={[pal.text, styles.noResult]}>
-              No result
+              <Trans>No result</Trans>
             </Text>
           )}
         </View>
diff --git a/src/view/com/feeds/FeedPage.tsx b/src/view/com/feeds/FeedPage.tsx
index 84d49e3b0..2d0b17f38 100644
--- a/src/view/com/feeds/FeedPage.tsx
+++ b/src/view/com/feeds/FeedPage.tsx
@@ -197,7 +197,7 @@ export function FeedPage({
           onPress={onPressCompose}
           icon={<ComposeIcon2 strokeWidth={1.5} size={29} style={s.white} />}
           accessibilityRole="button"
-          accessibilityLabel={_(msg`New post`)}
+          accessibilityLabel={_(msg({message: `New post`, context: 'action'}))}
           accessibilityHint=""
         />
       )}
diff --git a/src/view/com/feeds/FeedSourceCard.tsx b/src/view/com/feeds/FeedSourceCard.tsx
index 338ffc3d0..487163840 100644
--- a/src/view/com/feeds/FeedSourceCard.tsx
+++ b/src/view/com/feeds/FeedSourceCard.tsx
@@ -14,7 +14,7 @@ import * as Toast from 'view/com/util/Toast'
 import {sanitizeHandle} from 'lib/strings/handles'
 import {logger} from '#/logger'
 import {useModalControls} from '#/state/modals'
-import {msg} from '@lingui/macro'
+import {Trans, msg} from '@lingui/macro'
 import {useLingui} from '@lingui/react'
 import {
   usePinFeedMutation,
@@ -108,9 +108,9 @@ export function FeedSourceCardLoaded({
           try {
             await removeFeed({uri: feed.uri})
             // await item.unsave()
-            Toast.show('Removed from my feeds')
+            Toast.show(_(msg`Removed from my feeds`))
           } catch (e) {
-            Toast.show('There was an issue contacting your server')
+            Toast.show(_(msg`There was an issue contacting your server`))
             logger.error('Failed to unsave feed', {error: e})
           }
         },
@@ -122,9 +122,9 @@ export function FeedSourceCardLoaded({
         } else {
           await saveFeed({uri: feed.uri})
         }
-        Toast.show('Added to my feeds')
+        Toast.show(_(msg`Added to my feeds`))
       } catch (e) {
-        Toast.show('There was an issue contacting your server')
+        Toast.show(_(msg`There was an issue contacting your server`))
         logger.error('Failed to save feed', {error: e})
       }
     }
@@ -164,7 +164,7 @@ export function FeedSourceCardLoaded({
             testID={`feed-${feedUri}-toggleSave`}
             disabled={isRemovePending}
             accessibilityRole="button"
-            accessibilityLabel={'Remove from my feeds'}
+            accessibilityLabel={_(msg`Remove from my feeds`)}
             accessibilityHint=""
             onPress={() => {
               openModal({
@@ -175,9 +175,11 @@ export function FeedSourceCardLoaded({
                   try {
                     await removeFeed({uri: feedUri})
                     // await item.unsave()
-                    Toast.show('Removed from my feeds')
+                    Toast.show(_(msg`Removed from my feeds`))
                   } catch (e) {
-                    Toast.show('There was an issue contacting your server')
+                    Toast.show(
+                      _(msg`There was an issue contacting your server`),
+                    )
                     logger.error('Failed to unsave feed', {error: e})
                   }
                 },
@@ -223,8 +225,11 @@ export function FeedSourceCardLoaded({
             {feed.displayName}
           </Text>
           <Text style={[pal.textLight]} numberOfLines={3}>
-            {feed.type === 'feed' ? 'Feed' : 'List'} by{' '}
-            {sanitizeHandle(feed.creatorHandle, '@')}
+            {feed.type === 'feed' ? (
+              <Trans>Feed by {sanitizeHandle(feed.creatorHandle, '@')}</Trans>
+            ) : (
+              <Trans>List by {sanitizeHandle(feed.creatorHandle, '@')}</Trans>
+            )}
           </Text>
         </View>
 
@@ -235,7 +240,7 @@ export function FeedSourceCardLoaded({
               disabled={isSavePending || isPinPending || isRemovePending}
               accessibilityRole="button"
               accessibilityLabel={
-                isSaved ? 'Remove from my feeds' : 'Add to my feeds'
+                isSaved ? _(msg`Remove from my feeds`) : _(msg`Add to my feeds`)
               }
               accessibilityHint=""
               onPress={onToggleSaved}
@@ -269,8 +274,10 @@ export function FeedSourceCardLoaded({
 
       {showLikes && feed.type === 'feed' ? (
         <Text type="sm-medium" style={[pal.text, pal.textLight]}>
-          Liked by {feed.likeCount || 0}{' '}
-          {pluralize(feed.likeCount || 0, 'user')}
+          <Trans>
+            Liked by {feed.likeCount || 0}{' '}
+            {pluralize(feed.likeCount || 0, 'user')}
+          </Trans>
         </Text>
       ) : null}
     </Pressable>
diff --git a/src/view/com/feeds/ProfileFeedgens.tsx b/src/view/com/feeds/ProfileFeedgens.tsx
index 8665fbfac..f558eb18c 100644
--- a/src/view/com/feeds/ProfileFeedgens.tsx
+++ b/src/view/com/feeds/ProfileFeedgens.tsx
@@ -9,13 +9,14 @@ import {Text} from '../util/text/Text'
 import {usePalette} from 'lib/hooks/usePalette'
 import {useProfileFeedgensQuery, RQKEY} from '#/state/queries/profile-feedgens'
 import {logger} from '#/logger'
-import {Trans} from '@lingui/macro'
+import {Trans, msg} from '@lingui/macro'
 import {cleanError} from '#/lib/strings/errors'
 import {useTheme} from '#/lib/ThemeContext'
 import {usePreferencesQuery} from '#/state/queries/preferences'
 import {hydrateFeedGenerator} from '#/state/queries/feed'
 import {FeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder'
 import {isNative} from '#/platform/detection'
+import {useLingui} from '@lingui/react'
 
 const LOADING = {_reactKey: '__loading__'}
 const EMPTY = {_reactKey: '__empty__'}
@@ -43,6 +44,7 @@ export const ProfileFeedgens = React.forwardRef<
   ref,
 ) {
   const pal = usePalette('default')
+  const {_} = useLingui()
   const theme = useTheme()
   const [isPTRing, setIsPTRing] = React.useState(false)
   const opts = React.useMemo(() => ({enabled}), [enabled])
@@ -142,7 +144,9 @@ export const ProfileFeedgens = React.forwardRef<
       } else if (item === LOAD_MORE_ERROR_ITEM) {
         return (
           <LoadMoreRetryBtn
-            label="There was an issue fetching your lists. Tap here to try again."
+            label={_(
+              msg`There was an issue fetching your lists. Tap here to try again.`,
+            )}
             onPress={onPressRetryLoadMore}
           />
         )
@@ -162,7 +166,7 @@ export const ProfileFeedgens = React.forwardRef<
       }
       return null
     },
-    [error, refetch, onPressRetryLoadMore, pal, preferences],
+    [error, refetch, onPressRetryLoadMore, pal, preferences, _],
   )
 
   return (
diff --git a/src/view/com/lightbox/ImageViewing/components/ImageDefaultHeader.tsx b/src/view/com/lightbox/ImageViewing/components/ImageDefaultHeader.tsx
index c806bc6a6..3401adaff 100644
--- a/src/view/com/lightbox/ImageViewing/components/ImageDefaultHeader.tsx
+++ b/src/view/com/lightbox/ImageViewing/components/ImageDefaultHeader.tsx
@@ -24,7 +24,7 @@ const ImageDefaultHeader = ({onRequestClose}: Props) => (
       hitSlop={HIT_SLOP}
       accessibilityRole="button"
       accessibilityLabel={t`Close image`}
-      accessibilityHint="Closes viewer for header image"
+      accessibilityHint={t`Closes viewer for header image`}
       onAccessibilityEscape={onRequestClose}>
       <Text style={styles.closeText}>✕</Text>
     </TouchableOpacity>
diff --git a/src/view/com/lightbox/Lightbox.tsx b/src/view/com/lightbox/Lightbox.tsx
index 8a18df33f..2271bb9fb 100644
--- a/src/view/com/lightbox/Lightbox.tsx
+++ b/src/view/com/lightbox/Lightbox.tsx
@@ -15,6 +15,8 @@ import {
   ProfileImageLightbox,
   ImagesLightbox,
 } from '#/state/lightbox'
+import {Trans, msg} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
 
 export function Lightbox() {
   const {activeLightbox} = useLightbox()
@@ -53,6 +55,7 @@ export function Lightbox() {
 }
 
 function LightboxFooter({imageIndex}: {imageIndex: number}) {
+  const {_} = useLingui()
   const {activeLightbox} = useLightbox()
   const [isAltExpanded, setAltExpanded] = React.useState(false)
   const [permissionResponse, requestPermission] = MediaLibrary.usePermissions()
@@ -60,12 +63,14 @@ function LightboxFooter({imageIndex}: {imageIndex: number}) {
   const saveImageToAlbumWithToasts = React.useCallback(
     async (uri: string) => {
       if (!permissionResponse || permissionResponse.granted === false) {
-        Toast.show('Permission to access camera roll is required.')
+        Toast.show(_(msg`Permission to access camera roll is required.`))
         if (permissionResponse?.canAskAgain) {
           requestPermission()
         } else {
           Toast.show(
-            'Permission to access camera roll was denied. Please enable it in your system settings.',
+            _(
+              msg`Permission to access camera roll was denied. Please enable it in your system settings.`,
+            ),
           )
         }
         return
@@ -78,7 +83,7 @@ function LightboxFooter({imageIndex}: {imageIndex: number}) {
         Toast.show(`Failed to save image: ${String(e)}`)
       }
     },
-    [permissionResponse, requestPermission],
+    [permissionResponse, requestPermission, _],
   )
 
   const lightbox = activeLightbox
@@ -117,7 +122,7 @@ function LightboxFooter({imageIndex}: {imageIndex: number}) {
           onPress={() => saveImageToAlbumWithToasts(uri)}>
           <FontAwesomeIcon icon={['far', 'floppy-disk']} style={s.white} />
           <Text type="xl" style={s.white}>
-            Save
+            <Trans context="action">Save</Trans>
           </Text>
         </Button>
         <Button
@@ -126,7 +131,7 @@ function LightboxFooter({imageIndex}: {imageIndex: number}) {
           onPress={() => shareImageModal({uri})}>
           <FontAwesomeIcon icon="arrow-up-from-bracket" style={s.white} />
           <Text type="xl" style={s.white}>
-            Share
+            <Trans context="action">Share</Trans>
           </Text>
         </Button>
       </View>
diff --git a/src/view/com/lightbox/Lightbox.web.tsx b/src/view/com/lightbox/Lightbox.web.tsx
index 45e1fa5a3..a258d25ab 100644
--- a/src/view/com/lightbox/Lightbox.web.tsx
+++ b/src/view/com/lightbox/Lightbox.web.tsx
@@ -110,7 +110,7 @@ function LightboxInner({
         onPress={onClose}
         accessibilityRole="button"
         accessibilityLabel={_(msg`Close image viewer`)}
-        accessibilityHint="Exits image view"
+        accessibilityHint={_(msg`Exits image view`)}
         onAccessibilityEscape={onClose}>
         <View style={styles.imageCenterer}>
           <Image
@@ -154,7 +154,9 @@ function LightboxInner({
         <View style={styles.footer}>
           <Pressable
             accessibilityLabel={_(msg`Expand alt text`)}
-            accessibilityHint="If alt text is long, toggles alt text expanded state"
+            accessibilityHint={_(
+              msg`If alt text is long, toggles alt text expanded state`,
+            )}
             onPress={() => {
               setAltExpanded(!isAltExpanded)
             }}>
diff --git a/src/view/com/lists/ListCard.tsx b/src/view/com/lists/ListCard.tsx
index 774e9e916..28e98144a 100644
--- a/src/view/com/lists/ListCard.tsx
+++ b/src/view/com/lists/ListCard.tsx
@@ -11,6 +11,7 @@ import {useSession} from '#/state/session'
 import {sanitizeDisplayName} from 'lib/strings/display-names'
 import {sanitizeHandle} from 'lib/strings/handles'
 import {makeProfileLink} from 'lib/routes/links'
+import {Trans} from '@lingui/macro'
 
 export const ListCard = ({
   testID,
@@ -76,19 +77,28 @@ export const ListCard = ({
             {sanitizeDisplayName(list.name)}
           </Text>
           <Text type="md" style={[pal.textLight]} numberOfLines={1}>
-            {list.purpose === 'app.bsky.graph.defs#curatelist' && 'User list '}
+            {list.purpose === 'app.bsky.graph.defs#curatelist' &&
+              (list.creator.did === currentAccount?.did ? (
+                <Trans>User list by you</Trans>
+              ) : (
+                <Trans>
+                  User list by {sanitizeHandle(list.creator.handle, '@')}
+                </Trans>
+              ))}
             {list.purpose === 'app.bsky.graph.defs#modlist' &&
-              'Moderation list '}
-            by{' '}
-            {list.creator.did === currentAccount?.did
-              ? 'you'
-              : sanitizeHandle(list.creator.handle, '@')}
+              (list.creator.did === currentAccount?.did ? (
+                <Trans>Moderation list by you</Trans>
+              ) : (
+                <Trans>
+                  Moderation list by {sanitizeHandle(list.creator.handle, '@')}
+                </Trans>
+              ))}
           </Text>
           {!!list.viewer?.muted && (
             <View style={s.flexRow}>
               <View style={[s.mt5, pal.btn, styles.pill]}>
                 <Text type="xs" style={pal.text}>
-                  Subscribed
+                  <Trans>Subscribed</Trans>
                 </Text>
               </View>
             </View>
diff --git a/src/view/com/lists/ListMembers.tsx b/src/view/com/lists/ListMembers.tsx
index 932f4b512..212244cd8 100644
--- a/src/view/com/lists/ListMembers.tsx
+++ b/src/view/com/lists/ListMembers.tsx
@@ -20,6 +20,8 @@ import {logger} from '#/logger'
 import {useModalControls} from '#/state/modals'
 import {useSession} from '#/state/session'
 import {cleanError} from '#/lib/strings/errors'
+import {useLingui} from '@lingui/react'
+import {msg} from '@lingui/macro'
 
 const LOADING_ITEM = {_reactKey: '__loading__'}
 const EMPTY_ITEM = {_reactKey: '__empty__'}
@@ -50,6 +52,7 @@ export function ListMembers({
   desktopFixedHeightOffset?: number
 }) {
   const {track} = useAnalytics()
+  const {_} = useLingui()
   const [isRefreshing, setIsRefreshing] = React.useState(false)
   const {isMobile} = useWebMediaQueries()
   const {openModal} = useModalControls()
@@ -143,12 +146,12 @@ export function ListMembers({
         <Button
           testID={`user-${profile.handle}-editBtn`}
           type="default"
-          label="Edit"
+          label={_(msg({message: 'Edit', context: 'action'}))}
           onPress={() => onPressEditMembership(profile)}
         />
       )
     },
-    [isOwner, onPressEditMembership],
+    [isOwner, onPressEditMembership, _],
   )
 
   const renderItem = React.useCallback(
@@ -165,7 +168,9 @@ export function ListMembers({
       } else if (item === LOAD_MORE_ERROR_ITEM) {
         return (
           <LoadMoreRetryBtn
-            label="There was an issue fetching the list. Tap here to try again."
+            label={_(
+              msg`There was an issue fetching the list. Tap here to try again.`,
+            )}
             onPress={onPressRetryLoadMore}
           />
         )
@@ -191,6 +196,7 @@ export function ListMembers({
       onPressTryAgain,
       onPressRetryLoadMore,
       isMobile,
+      _,
     ],
   )
 
diff --git a/src/view/com/lists/ProfileLists.tsx b/src/view/com/lists/ProfileLists.tsx
index db981717f..89d6ab480 100644
--- a/src/view/com/lists/ProfileLists.tsx
+++ b/src/view/com/lists/ProfileLists.tsx
@@ -10,11 +10,12 @@ import {useAnalytics} from 'lib/analytics/analytics'
 import {usePalette} from 'lib/hooks/usePalette'
 import {useProfileListsQuery, RQKEY} from '#/state/queries/profile-lists'
 import {logger} from '#/logger'
-import {Trans} from '@lingui/macro'
+import {Trans, msg} from '@lingui/macro'
 import {cleanError} from '#/lib/strings/errors'
 import {useTheme} from '#/lib/ThemeContext'
 import {FeedLoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder'
 import {isNative} from '#/platform/detection'
+import {useLingui} from '@lingui/react'
 
 const LOADING = {_reactKey: '__loading__'}
 const EMPTY = {_reactKey: '__empty__'}
@@ -42,6 +43,7 @@ export const ProfileLists = React.forwardRef<SectionRef, ProfileListsProps>(
     const pal = usePalette('default')
     const theme = useTheme()
     const {track} = useAnalytics()
+    const {_} = useLingui()
     const [isPTRing, setIsPTRing] = React.useState(false)
     const opts = React.useMemo(() => ({enabled}), [enabled])
     const {
@@ -149,7 +151,9 @@ export const ProfileLists = React.forwardRef<SectionRef, ProfileListsProps>(
         } else if (item === LOAD_MORE_ERROR_ITEM) {
           return (
             <LoadMoreRetryBtn
-              label="There was an issue fetching your lists. Tap here to try again."
+              label={_(
+                msg`There was an issue fetching your lists. Tap here to try again.`,
+              )}
               onPress={onPressRetryLoadMore}
             />
           )
@@ -164,7 +168,7 @@ export const ProfileLists = React.forwardRef<SectionRef, ProfileListsProps>(
           />
         )
       },
-      [error, refetch, onPressRetryLoadMore, pal],
+      [error, refetch, onPressRetryLoadMore, pal, _],
     )
 
     return (
diff --git a/src/view/com/modals/AddAppPasswords.tsx b/src/view/com/modals/AddAppPasswords.tsx
index 812a36f45..7ec8268be 100644
--- a/src/view/com/modals/AddAppPasswords.tsx
+++ b/src/view/com/modals/AddAppPasswords.tsx
@@ -72,10 +72,10 @@ export function Component({}: {}) {
   const onCopy = React.useCallback(() => {
     if (appPassword) {
       Clipboard.setString(appPassword)
-      Toast.show('Copied to clipboard')
+      Toast.show(_(msg`Copied to clipboard`))
       setWasCopied(true)
     }
-  }, [appPassword])
+  }, [appPassword, _])
 
   const onDone = React.useCallback(() => {
     closeModal()
@@ -85,7 +85,9 @@ export function Component({}: {}) {
     // if name is all whitespace, we don't allow it
     if (!name || !name.trim()) {
       Toast.show(
-        'Please enter a name for your app password. All spaces is not allowed.',
+        _(
+          msg`Please enter a name for your app password. All spaces is not allowed.`,
+        ),
         'times',
       )
       return
@@ -93,14 +95,14 @@ export function Component({}: {}) {
     // if name is too short (under 4 chars), we don't allow it
     if (name.length < 4) {
       Toast.show(
-        'App Password names must be at least 4 characters long.',
+        _(msg`App Password names must be at least 4 characters long.`),
         'times',
       )
       return
     }
 
     if (passwords?.find(p => p.name === name)) {
-      Toast.show('This name is already in use', 'times')
+      Toast.show(_(msg`This name is already in use`), 'times')
       return
     }
 
@@ -109,11 +111,11 @@ export function Component({}: {}) {
       if (newPassword) {
         setAppPassword(newPassword.password)
       } else {
-        Toast.show('Failed to create app password.', 'times')
+        Toast.show(_(msg`Failed to create app password.`), 'times')
         // TODO: better error handling (?)
       }
     } catch (e) {
-      Toast.show('Failed to create app password.', 'times')
+      Toast.show(_(msg`Failed to create app password.`), 'times')
       logger.error('Failed to create app password', {error: e})
     }
   }
@@ -127,7 +129,9 @@ export function Component({}: {}) {
       setName(text)
     } else {
       Toast.show(
-        'App Password names can only contain letters, numbers, spaces, dashes, and underscores.',
+        _(
+          msg`App Password names can only contain letters, numbers, spaces, dashes, and underscores.`,
+        ),
       )
     }
   }
@@ -158,7 +162,7 @@ export function Component({}: {}) {
               style={[styles.input, pal.text]}
               onChangeText={_onChangeText}
               value={name}
-              placeholder="Enter a name for this App Password"
+              placeholder={_(msg`Enter a name for this App Password`)}
               placeholderTextColor={pal.colors.textLight}
               autoCorrect={false}
               autoComplete="off"
@@ -175,7 +179,7 @@ export function Component({}: {}) {
               onEndEditing={createAppPassword}
               accessible={true}
               accessibilityLabel={_(msg`Name`)}
-              accessibilityHint="Input name for app password"
+              accessibilityHint={_(msg`Input name for app password`)}
             />
           </View>
         ) : (
@@ -184,7 +188,7 @@ export function Component({}: {}) {
             onPress={onCopy}
             accessibilityRole="button"
             accessibilityLabel={_(msg`Copy`)}
-            accessibilityHint="Copies app password">
+            accessibilityHint={_(msg`Copies app password`)}>
             <Text type="2xl-bold" style={[pal.text]}>
               {appPassword}
             </Text>
@@ -221,7 +225,7 @@ export function Component({}: {}) {
       <View style={styles.btnContainer}>
         <Button
           type="primary"
-          label={!appPassword ? 'Create App Password' : 'Done'}
+          label={!appPassword ? _(msg`Create App Password`) : _(msg`Done`)}
           style={styles.btn}
           labelStyle={styles.btnLabel}
           onPress={!appPassword ? createAppPassword : onDone}
diff --git a/src/view/com/modals/AppealLabel.tsx b/src/view/com/modals/AppealLabel.tsx
index edc6f4cd0..1a1947a9a 100644
--- a/src/view/com/modals/AppealLabel.tsx
+++ b/src/view/com/modals/AppealLabel.tsx
@@ -45,7 +45,7 @@ export function Component(props: ReportComponentProps) {
         },
         reason: details,
       })
-      Toast.show("We'll look into your appeal promptly.")
+      Toast.show(_(msg`We'll look into your appeal promptly.`))
     } finally {
       closeModal()
     }
diff --git a/src/view/com/modals/BirthDateSettings.tsx b/src/view/com/modals/BirthDateSettings.tsx
index 1505d224f..5ebc61137 100644
--- a/src/view/com/modals/BirthDateSettings.tsx
+++ b/src/view/com/modals/BirthDateSettings.tsx
@@ -71,7 +71,7 @@ function Inner({preferences}: {preferences: UsePreferencesQueryResponse}) {
           buttonStyle={[pal.border, styles.dateInputButton]}
           buttonLabelType="lg"
           accessibilityLabel={_(msg`Birthday`)}
-          accessibilityHint="Enter your birth date"
+          accessibilityHint={_(msg`Enter your birth date`)}
           accessibilityLabelledBy="birthDate"
         />
       </View>
diff --git a/src/view/com/modals/ChangeEmail.tsx b/src/view/com/modals/ChangeEmail.tsx
index 44b102fa0..c5672bc81 100644
--- a/src/view/com/modals/ChangeEmail.tsx
+++ b/src/view/com/modals/ChangeEmail.tsx
@@ -38,7 +38,7 @@ export function Component() {
 
   const onRequestChange = async () => {
     if (email === currentAccount?.email) {
-      setError('Enter your new email above')
+      setError(_(msg`Enter your new email above`))
       return
     }
     setError('')
@@ -53,7 +53,7 @@ export function Component() {
           email: email.trim(),
           emailConfirmed: false,
         })
-        Toast.show('Email updated')
+        Toast.show(_(msg`Email updated`))
         setStage(Stages.Done)
       }
     } catch (e) {
@@ -85,7 +85,7 @@ export function Component() {
         email: email.trim(),
         emailConfirmed: false,
       })
-      Toast.show('Email updated')
+      Toast.show(_(msg`Email updated`))
       setStage(Stages.Done)
     } catch (e) {
       setError(cleanError(String(e)))
diff --git a/src/view/com/modals/ChangeHandle.tsx b/src/view/com/modals/ChangeHandle.tsx
index 31f6d6ea7..e578fa7da 100644
--- a/src/view/com/modals/ChangeHandle.tsx
+++ b/src/view/com/modals/ChangeHandle.tsx
@@ -147,7 +147,7 @@ export function Inner({
             onPress={onPressCancel}
             accessibilityRole="button"
             accessibilityLabel={_(msg`Cancel change handle`)}
-            accessibilityHint="Exits handle change process"
+            accessibilityHint={_(msg`Exits handle change process`)}
             onAccessibilityEscape={onPressCancel}>
             <Text type="lg" style={pal.textLight}>
               Cancel
@@ -168,7 +168,7 @@ export function Inner({
               onPress={onPressSave}
               accessibilityRole="button"
               accessibilityLabel={_(msg`Save handle change`)}
-              accessibilityHint={`Saves handle change to ${handle}`}>
+              accessibilityHint={_(msg`Saves handle change to ${handle}`)}>
               <Text type="2xl-medium" style={pal.link}>
                 <Trans>Save</Trans>
               </Text>
@@ -263,14 +263,16 @@ function ProvidedHandleForm({
           editable={!isProcessing}
           accessible={true}
           accessibilityLabel={_(msg`Handle`)}
-          accessibilityHint="Sets Bluesky username"
+          accessibilityHint={_(msg`Sets Bluesky username`)}
         />
       </View>
       <Text type="md" style={[pal.textLight, s.pl10, s.pt10]}>
-        <Trans>Your full handle will be</Trans>{' '}
-        <Text type="md-bold" style={pal.textLight}>
-          @{createFullHandle(handle, userDomain)}
-        </Text>
+        <Trans>
+          Your full handle will be{' '}
+          <Text type="md-bold" style={pal.textLight}>
+            @{createFullHandle(handle, userDomain)}
+          </Text>
+        </Trans>
       </Text>
       <TouchableOpacity
         onPress={onToggleCustom}
diff --git a/src/view/com/modals/Confirm.tsx b/src/view/com/modals/Confirm.tsx
index 5e869f396..307897fb8 100644
--- a/src/view/com/modals/Confirm.tsx
+++ b/src/view/com/modals/Confirm.tsx
@@ -12,7 +12,7 @@ import {cleanError} from 'lib/strings/errors'
 import {usePalette} from 'lib/hooks/usePalette'
 import {isWeb} from 'platform/detection'
 import {useLingui} from '@lingui/react'
-import {msg} from '@lingui/macro'
+import {Trans, msg} from '@lingui/macro'
 import type {ConfirmModal} from '#/state/modals'
 import {useModalControls} from '#/state/modals'
 
@@ -72,10 +72,10 @@ export function Component({
           onPress={onPress}
           style={[styles.btn, confirmBtnStyle]}
           accessibilityRole="button"
-          accessibilityLabel={_(msg`Confirm`)}
+          accessibilityLabel={_(msg({message: 'Confirm', context: 'action'}))}
           accessibilityHint="">
           <Text style={[s.white, s.bold, s.f18]}>
-            {confirmBtnText ?? 'Confirm'}
+            {confirmBtnText ?? <Trans context="action">Confirm</Trans>}
           </Text>
         </TouchableOpacity>
       )}
@@ -85,10 +85,10 @@ export function Component({
           onPress={onPressCancel}
           style={[styles.btnCancel, s.mt10]}
           accessibilityRole="button"
-          accessibilityLabel={_(msg`Cancel`)}
+          accessibilityLabel={_(msg({message: 'Cancel', context: 'action'}))}
           accessibilityHint="">
           <Text type="button-lg" style={pal.textLight}>
-            {cancelBtnText ?? 'Cancel'}
+            {cancelBtnText ?? <Trans context="action">Cancel</Trans>}
           </Text>
         </TouchableOpacity>
       )}
diff --git a/src/view/com/modals/ContentFilteringSettings.tsx b/src/view/com/modals/ContentFilteringSettings.tsx
index 88fb43443..d681fbf0b 100644
--- a/src/view/com/modals/ContentFilteringSettings.tsx
+++ b/src/view/com/modals/ContentFilteringSettings.tsx
@@ -148,9 +148,13 @@ function AdultContentEnabledPref() {
       ) : typeof preferences?.birthDate === 'undefined' ? (
         <View style={[pal.viewLight, styles.agePrompt]}>
           <Text type="md" style={[pal.text, {flex: 1}]}>
-            Confirm your age to enable adult content.
+            <Trans>Confirm your age to enable adult content.</Trans>
           </Text>
-          <Button type="primary" label="Set Age" onPress={onSetAge} />
+          <Button
+            type="primary"
+            label={_(msg({message: 'Set Age', context: 'action'}))}
+            onPress={onSetAge}
+          />
         </View>
       ) : (preferences.userAge || 0) >= 18 ? (
         <ToggleButton
@@ -165,7 +169,11 @@ function AdultContentEnabledPref() {
           <Text type="md" style={[pal.text, {flex: 1}]}>
             <Trans>You must be 18 or older to enable adult content.</Trans>
           </Text>
-          <Button type="primary" label="Set Age" onPress={onSetAge} />
+          <Button
+            type="primary"
+            label={_(msg({message: 'Set Age', context: 'action'}))}
+            onPress={onSetAge}
+          />
         </View>
       )}
     </View>
@@ -208,7 +216,7 @@ function ContentLabelPref({
 
       {disabled || !visibility ? (
         <Text type="sm-bold" style={pal.textLight}>
-          <Trans>Hide</Trans>
+          <Trans context="action">Hide</Trans>
         </Text>
       ) : (
         <SelectGroup
@@ -229,6 +237,7 @@ interface SelectGroupProps {
 
 function SelectGroup({current, onChange, labelGroup}: SelectGroupProps) {
   const {_} = useLingui()
+
   return (
     <View style={styles.selectableBtns}>
       <SelectableBtn
@@ -279,6 +288,8 @@ function SelectableBtn({
 }: SelectableBtnProps) {
   const pal = usePalette('default')
   const palPrimary = usePalette('inverted')
+  const {_} = useLingui()
+
   return (
     <Pressable
       style={[
@@ -291,7 +302,9 @@ function SelectableBtn({
       onPress={() => onChange(value)}
       accessibilityRole="button"
       accessibilityLabel={value}
-      accessibilityHint={`Set ${value} for ${labelGroup} content moderation policy`}>
+      accessibilityHint={_(
+        msg`Set ${value} for ${labelGroup} content moderation policy`,
+      )}>
       <Text style={current === value ? palPrimary.text : pal.text}>
         {label}
       </Text>
diff --git a/src/view/com/modals/CreateOrEditList.tsx b/src/view/com/modals/CreateOrEditList.tsx
index 8d13cdf2f..bd1eb3393 100644
--- a/src/view/com/modals/CreateOrEditList.tsx
+++ b/src/view/com/modals/CreateOrEditList.tsx
@@ -65,7 +65,6 @@ export function Component({
     return 'app.bsky.graph.defs#curatelist'
   }, [list, purpose])
   const isCurateList = activePurpose === 'app.bsky.graph.defs#curatelist'
-  const purposeLabel = isCurateList ? 'User' : 'Moderation'
 
   const [isProcessing, setProcessing] = useState<boolean>(false)
   const [name, setName] = useState<string>(list?.name || '')
@@ -106,7 +105,7 @@ export function Component({
     }
     const nameTrimmed = name.trim()
     if (!nameTrimmed) {
-      setError('Name is required')
+      setError(_(msg`Name is required`))
       return
     }
     setProcessing(true)
@@ -121,7 +120,11 @@ export function Component({
           description: description.trim(),
           avatar: newAvatar,
         })
-        Toast.show(`${purposeLabel} list updated`)
+        Toast.show(
+          isCurateList
+            ? _(msg`User list updated`)
+            : _(msg`Moderation list updated`),
+        )
         onSave?.(list.uri)
       } else {
         const res = await listCreateMutation.mutateAsync({
@@ -130,14 +133,20 @@ export function Component({
           description,
           avatar: newAvatar,
         })
-        Toast.show(`${purposeLabel} list created`)
+        Toast.show(
+          isCurateList
+            ? _(msg`User list created`)
+            : _(msg`Moderation list created`),
+        )
         onSave?.(res.uri)
       }
       closeModal()
     } catch (e: any) {
       if (isNetworkError(e)) {
         setError(
-          'Failed to create the list. Check your internet connection and try again.',
+          _(
+            msg`Failed to create the list. Check your internet connection and try again.`,
+          ),
         )
       } else {
         setError(cleanError(e))
@@ -153,13 +162,13 @@ export function Component({
     closeModal,
     activePurpose,
     isCurateList,
-    purposeLabel,
     name,
     description,
     newAvatar,
     list,
     listMetadataMutation,
     listCreateMutation,
+    _,
   ])
 
   return (
@@ -174,7 +183,17 @@ export function Component({
         testID="createOrEditListModal">
         <Text style={[styles.title, pal.text]}>
           <Trans>
-            {list ? 'Edit' : 'New'} {purposeLabel} List
+            {isCurateList ? (
+              list ? (
+                <Trans>Edit User List</Trans>
+              ) : (
+                <Trans>New User List</Trans>
+              )
+            ) : list ? (
+              <Trans>Edit Moderation List</Trans>
+            ) : (
+              <Trans>New Moderation List</Trans>
+            )}
           </Trans>
         </Text>
         {error !== '' && (
@@ -202,7 +221,9 @@ export function Component({
               testID="editNameInput"
               style={[styles.textInput, pal.border, pal.text]}
               placeholder={
-                isCurateList ? 'e.g. Great Posters' : 'e.g. Spammers'
+                isCurateList
+                  ? _(msg`e.g. Great Posters`)
+                  : _(msg`e.g. Spammers`)
               }
               placeholderTextColor={colors.gray4}
               value={name}
@@ -222,8 +243,8 @@ export function Component({
               style={[styles.textArea, pal.border, pal.text]}
               placeholder={
                 isCurateList
-                  ? 'e.g. The posters who never miss.'
-                  : 'e.g. Users that repeatedly reply with ads.'
+                  ? _(msg`e.g. The posters who never miss.`)
+                  : _(msg`e.g. Users that repeatedly reply with ads.`)
               }
               placeholderTextColor={colors.gray4}
               keyboardAppearance={theme.colorScheme}
@@ -254,7 +275,7 @@ export function Component({
                 end={{x: 1, y: 1}}
                 style={[styles.btn]}>
                 <Text style={[s.white, s.bold]}>
-                  <Trans>Save</Trans>
+                  <Trans context="action">Save</Trans>
                 </Text>
               </LinearGradient>
             </TouchableOpacity>
@@ -269,7 +290,7 @@ export function Component({
             onAccessibilityEscape={onPressCancel}>
             <View style={[styles.btn]}>
               <Text style={[s.black, s.bold, pal.text]}>
-                <Trans>Cancel</Trans>
+                <Trans context="action">Cancel</Trans>
               </Text>
             </View>
           </TouchableOpacity>
diff --git a/src/view/com/modals/DeleteAccount.tsx b/src/view/com/modals/DeleteAccount.tsx
index ee16d46b3..0cfc098d4 100644
--- a/src/view/com/modals/DeleteAccount.tsx
+++ b/src/view/com/modals/DeleteAccount.tsx
@@ -62,7 +62,7 @@ export function Component({}: {}) {
         password,
         token,
       })
-      Toast.show('Your account has been deleted')
+      Toast.show(_(msg`Your account has been deleted`))
       resetToTab('HomeTab')
       removeAccount(currentAccount)
       clearCurrentAccount()
@@ -125,7 +125,9 @@ export function Component({}: {}) {
                   onPress={onPressSendEmail}
                   accessibilityRole="button"
                   accessibilityLabel={_(msg`Send email`)}
-                  accessibilityHint="Sends email with confirmation code for account deletion">
+                  accessibilityHint={_(
+                    msg`Sends email with confirmation code for account deletion`,
+                  )}>
                   <LinearGradient
                     colors={[
                       gradients.blueLight.start,
@@ -135,7 +137,7 @@ export function Component({}: {}) {
                     end={{x: 1, y: 1}}
                     style={[styles.btn]}>
                     <Text type="button-lg" style={[s.white, s.bold]}>
-                      <Trans>Send Email</Trans>
+                      <Trans context="action">Send Email</Trans>
                     </Text>
                   </LinearGradient>
                 </TouchableOpacity>
@@ -147,7 +149,7 @@ export function Component({}: {}) {
                   accessibilityHint=""
                   onAccessibilityEscape={onCancel}>
                   <Text type="button-lg" style={pal.textLight}>
-                    <Trans>Cancel</Trans>
+                    <Trans context="action">Cancel</Trans>
                   </Text>
                 </TouchableOpacity>
               </>
@@ -174,7 +176,9 @@ export function Component({}: {}) {
               onChangeText={setConfirmCode}
               accessibilityLabelledBy="confirmationCode"
               accessibilityLabel={_(msg`Confirmation code`)}
-              accessibilityHint="Input confirmation code for account deletion"
+              accessibilityHint={_(
+                msg`Input confirmation code for account deletion`,
+              )}
             />
             <Text type="lg" style={styles.description} nativeID="password">
               <Trans>Please enter your password as well:</Trans>
@@ -189,7 +193,7 @@ export function Component({}: {}) {
               onChangeText={setPassword}
               accessibilityLabelledBy="password"
               accessibilityLabel={_(msg`Password`)}
-              accessibilityHint="Input password for account deletion"
+              accessibilityHint={_(msg`Input password for account deletion`)}
             />
             {error ? (
               <View style={styles.mt20}>
@@ -220,7 +224,7 @@ export function Component({}: {}) {
                   accessibilityHint="Exits account deletion process"
                   onAccessibilityEscape={onCancel}>
                   <Text type="button-lg" style={pal.textLight}>
-                    <Trans>Cancel</Trans>
+                    <Trans context="action">Cancel</Trans>
                   </Text>
                 </TouchableOpacity>
               </>
diff --git a/src/view/com/modals/EditImage.tsx b/src/view/com/modals/EditImage.tsx
index 753907472..3b35ffee2 100644
--- a/src/view/com/modals/EditImage.tsx
+++ b/src/view/com/modals/EditImage.tsx
@@ -112,16 +112,16 @@ export const Component = observer(function EditImageImpl({
       // },
       {
         name: 'flip' as const,
-        label: 'Flip horizontal',
+        label: _(msg`Flip horizontal`),
         onPress: onFlipHorizontal,
       },
       {
         name: 'flip' as const,
-        label: 'Flip vertically',
+        label: _(msg`Flip vertically`),
         onPress: onFlipVertical,
       },
     ],
-    [onFlipHorizontal, onFlipVertical],
+    [onFlipHorizontal, onFlipVertical, _],
   )
 
   useEffect(() => {
@@ -284,7 +284,7 @@ export const Component = observer(function EditImageImpl({
                   size={label?.startsWith('Flip') ? 22 : 24}
                   style={[
                     pal.text,
-                    label === 'Flip vertically'
+                    label === _(msg`Flip vertically`)
                       ? styles.flipVertical
                       : undefined,
                   ]}
@@ -330,7 +330,7 @@ export const Component = observer(function EditImageImpl({
             end={{x: 1, y: 1}}
             style={[styles.btn]}>
             <Text type="xl-medium" style={s.white}>
-              <Trans>Done</Trans>
+              <Trans context="action">Done</Trans>
             </Text>
           </LinearGradient>
         </Pressable>
diff --git a/src/view/com/modals/EditProfile.tsx b/src/view/com/modals/EditProfile.tsx
index e044f8c0e..dd8ac9ae7 100644
--- a/src/view/com/modals/EditProfile.tsx
+++ b/src/view/com/modals/EditProfile.tsx
@@ -125,7 +125,7 @@ export function Component({
         newUserAvatar,
         newUserBanner,
       })
-      Toast.show('Profile updated')
+      Toast.show(_(msg`Profile updated`))
       onUpdate?.()
       closeModal()
     } catch (e: any) {
@@ -142,6 +142,7 @@ export function Component({
     newUserAvatar,
     newUserBanner,
     setImageError,
+    _,
   ])
 
   return (
@@ -181,7 +182,7 @@ export function Component({
             <TextInput
               testID="editProfileDisplayNameInput"
               style={[styles.textInput, pal.border, pal.text]}
-              placeholder="e.g. Alice Roberts"
+              placeholder={_(msg`e.g. Alice Roberts`)}
               placeholderTextColor={colors.gray4}
               value={displayName}
               onChangeText={v =>
@@ -189,7 +190,7 @@ export function Component({
               }
               accessible={true}
               accessibilityLabel={_(msg`Display name`)}
-              accessibilityHint="Edit your display name"
+              accessibilityHint={_(msg`Edit your display name`)}
             />
           </View>
           <View style={s.pb10}>
@@ -199,7 +200,7 @@ export function Component({
             <TextInput
               testID="editProfileDescriptionInput"
               style={[styles.textArea, pal.border, pal.text]}
-              placeholder="e.g. Artist, dog-lover, and avid reader."
+              placeholder={_(msg`e.g. Artist, dog-lover, and avid reader.`)}
               placeholderTextColor={colors.gray4}
               keyboardAppearance={theme.colorScheme}
               multiline
@@ -207,7 +208,7 @@ export function Component({
               onChangeText={v => setDescription(enforceLen(v, MAX_DESCRIPTION))}
               accessible={true}
               accessibilityLabel={_(msg`Description`)}
-              accessibilityHint="Edit your profile description"
+              accessibilityHint={_(msg`Edit your profile description`)}
             />
           </View>
           {updateMutation.isPending ? (
@@ -221,7 +222,7 @@ export function Component({
               onPress={onPressSave}
               accessibilityRole="button"
               accessibilityLabel={_(msg`Save`)}
-              accessibilityHint="Saves any changes to your profile">
+              accessibilityHint={_(msg`Saves any changes to your profile`)}>
               <LinearGradient
                 colors={[gradients.blueLight.start, gradients.blueLight.end]}
                 start={{x: 0, y: 0}}
diff --git a/src/view/com/modals/InviteCodes.tsx b/src/view/com/modals/InviteCodes.tsx
index a0bb5f4af..c0318df01 100644
--- a/src/view/com/modals/InviteCodes.tsx
+++ b/src/view/com/modals/InviteCodes.tsx
@@ -19,7 +19,6 @@ import {usePalette} from 'lib/hooks/usePalette'
 import {isWeb} from 'platform/detection'
 import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
 import {Trans, msg} from '@lingui/macro'
-import {useLingui} from '@lingui/react'
 import {cleanError} from 'lib/strings/errors'
 import {useModalControls} from '#/state/modals'
 import {useInvitesState, useInvitesAPI} from '#/state/invites'
@@ -31,6 +30,7 @@ import {
   useInviteCodesQuery,
   InviteCodesQueryResponse,
 } from '#/state/queries/invites'
+import {useLingui} from '@lingui/react'
 
 export const snapPoints = ['70%']
 
@@ -166,10 +166,10 @@ function InviteCode({
         accessibilityRole="button"
         accessibilityLabel={
           invites.available.length === 1
-            ? 'Invite codes: 1 available'
-            : `Invite codes: ${invites.available.length} available`
+            ? _(msg`Invite codes: 1 available`)
+            : _(msg`Invite codes: ${invites.available.length} available`)
         }
-        accessibilityHint="Opens list of invite codes">
+        accessibilityHint={_(msg`Opens list of invite codes`)}>
         <Text
           testID={`${testID}-code`}
           type={used ? 'md' : 'md-bold'}
diff --git a/src/view/com/modals/ListAddRemoveUsers.tsx b/src/view/com/modals/ListAddRemoveUsers.tsx
index 14e16d6bf..27c33f806 100644
--- a/src/view/com/modals/ListAddRemoveUsers.tsx
+++ b/src/view/com/modals/ListAddRemoveUsers.tsx
@@ -67,7 +67,7 @@ export function Component({
           <TextInput
             testID="searchInput"
             style={[styles.searchInput, pal.border, pal.text]}
-            placeholder="Search for users"
+            placeholder={_(msg`Search for users`)}
             placeholderTextColor={pal.colors.textLight}
             value={query}
             onChangeText={setQuery}
@@ -85,7 +85,7 @@ export function Component({
               onPress={onPressCancelSearch}
               accessibilityRole="button"
               accessibilityLabel={_(msg`Cancel search`)}
-              accessibilityHint="Exits inputting search query"
+              accessibilityHint={_(msg`Exits inputting search query`)}
               onAccessibilityEscape={onPressCancelSearch}
               hitSlop={HITSLOP_20}>
               <FontAwesomeIcon
@@ -141,7 +141,7 @@ export function Component({
             }}
             accessibilityLabel={_(msg`Done`)}
             accessibilityHint=""
-            label="Done"
+            label={_(msg({message: 'Done', context: 'action'}))}
             labelContainerStyle={{justifyContent: 'center', padding: 4}}
             labelStyle={[s.f18]}
           />
diff --git a/src/view/com/modals/ModerationDetails.tsx b/src/view/com/modals/ModerationDetails.tsx
index c117023d4..ba7f76db1 100644
--- a/src/view/com/modals/ModerationDetails.tsx
+++ b/src/view/com/modals/ModerationDetails.tsx
@@ -10,6 +10,8 @@ import {isWeb} from 'platform/detection'
 import {listUriToHref} from 'lib/strings/url-helpers'
 import {Button} from '../util/forms/Button'
 import {useModalControls} from '#/state/modals'
+import {useLingui} from '@lingui/react'
+import {Trans, msg} from '@lingui/macro'
 
 export const snapPoints = [300]
 
@@ -23,19 +25,21 @@ export function Component({
   const {closeModal} = useModalControls()
   const {isMobile} = useWebMediaQueries()
   const pal = usePalette('default')
+  const {_} = useLingui()
 
   let name
   let description
   if (!moderation.cause) {
-    name = 'Content Warning'
-    description =
-      'Moderator has chosen to set a general warning on the content.'
+    name = _(msg`Content Warning`)
+    description = _(
+      msg`Moderator has chosen to set a general warning on the content.`,
+    )
   } else if (moderation.cause.type === 'blocking') {
     if (moderation.cause.source.type === 'list') {
       const list = moderation.cause.source.list
-      name = 'User Blocked by List'
+      name = _(msg`User Blocked by List`)
       description = (
-        <>
+        <Trans>
           This user is included in the{' '}
           <TextLink
             type="2xl"
@@ -44,25 +48,30 @@ export function Component({
             style={pal.link}
           />{' '}
           list which you have blocked.
-        </>
+        </Trans>
       )
     } else {
-      name = 'User Blocked'
-      description = 'You have blocked this user. You cannot view their content.'
+      name = _(msg`User Blocked`)
+      description = _(
+        msg`You have blocked this user. You cannot view their content.`,
+      )
     }
   } else if (moderation.cause.type === 'blocked-by') {
-    name = 'User Blocks You'
-    description = 'This user has blocked you. You cannot view their content.'
+    name = _(msg`User Blocks You`)
+    description = _(
+      msg`This user has blocked you. You cannot view their content.`,
+    )
   } else if (moderation.cause.type === 'block-other') {
-    name = 'Content Not Available'
-    description =
-      'This content is not available because one of the users involved has blocked the other.'
+    name = _(msg`Content Not Available`)
+    description = _(
+      msg`This content is not available because one of the users involved has blocked the other.`,
+    )
   } else if (moderation.cause.type === 'muted') {
     if (moderation.cause.source.type === 'list') {
       const list = moderation.cause.source.list
-      name = <>Account Muted by List</>
+      name = _(msg`Account Muted by List`)
       description = (
-        <>
+        <Trans>
           This user is included the{' '}
           <TextLink
             type="2xl"
@@ -71,11 +80,11 @@ export function Component({
             style={pal.link}
           />{' '}
           list which you have muted.
-        </>
+        </Trans>
       )
     } else {
-      name = 'Account Muted'
-      description = 'You have muted this user.'
+      name = _(msg`Account Muted`)
+      description = _(msg`You have muted this user.`)
     }
   } else {
     name = moderation.cause.labelDef.strings[context].en.name
diff --git a/src/view/com/modals/ProfilePreview.tsx b/src/view/com/modals/ProfilePreview.tsx
index edfbf6a82..77e68db70 100644
--- a/src/view/com/modals/ProfilePreview.tsx
+++ b/src/view/com/modals/ProfilePreview.tsx
@@ -14,11 +14,14 @@ import {ErrorScreen} from '../util/error/ErrorScreen'
 import {CenteredView} from '../util/Views'
 import {cleanError} from '#/lib/strings/errors'
 import {useProfileShadow} from '#/state/cache/profile-shadow'
+import {Trans, msg} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
 
 export const snapPoints = [520, '100%']
 
 export function Component({did}: {did: string}) {
   const pal = usePalette('default')
+  const {_} = useLingui()
   const moderationOpts = useModerationOpts()
   const {
     data: profile,
@@ -43,7 +46,7 @@ export function Component({did}: {did: string}) {
   if (profileError) {
     return (
       <ErrorScreen
-        title="Oops!"
+        title={_(msg`Oops!`)}
         message={cleanError(profileError)}
         onPressTryAgain={refetchProfile}
       />
@@ -55,8 +58,8 @@ export function Component({did}: {did: string}) {
   // should never happen
   return (
     <ErrorScreen
-      title="Oops!"
-      message="Something went wrong and we're not sure what."
+      title={_(msg`Oops!`)}
+      message={_(msg`Something went wrong and we're not sure what.`)}
       onPressTryAgain={refetchProfile}
     />
   )
@@ -104,7 +107,7 @@ function ComponentLoaded({
             <>
               <InfoCircleIcon size={21} style={pal.textLight} />
               <ThemedText type="xl" fg="light">
-                Swipe up to see more
+                <Trans>Swipe up to see more</Trans>
               </ThemedText>
             </>
           )}
diff --git a/src/view/com/modals/Repost.tsx b/src/view/com/modals/Repost.tsx
index a72da29b4..6e4881adc 100644
--- a/src/view/com/modals/Repost.tsx
+++ b/src/view/com/modals/Repost.tsx
@@ -37,11 +37,23 @@ export function Component({
           style={[styles.actionBtn]}
           onPress={onRepost}
           accessibilityRole="button"
-          accessibilityLabel={isReposted ? 'Undo repost' : 'Repost'}
-          accessibilityHint={isReposted ? 'Remove repost' : 'Repost '}>
+          accessibilityLabel={
+            isReposted
+              ? _(msg`Undo repost`)
+              : _(msg({message: `Repost`, context: 'action'}))
+          }
+          accessibilityHint={
+            isReposted
+              ? _(msg`Remove repost`)
+              : _(msg({message: `Repost`, context: 'action'}))
+          }>
           <RepostIcon strokeWidth={2} size={24} style={s.blue3} />
           <Text type="title-lg" style={[styles.actionBtnLabel, pal.text]}>
-            <Trans>{!isReposted ? 'Repost' : 'Undo repost'}</Trans>
+            {!isReposted ? (
+              <Trans context="action">Repost</Trans>
+            ) : (
+              <Trans>Undo repost</Trans>
+            )}
           </Text>
         </TouchableOpacity>
         <TouchableOpacity
@@ -49,11 +61,13 @@ export function Component({
           style={[styles.actionBtn]}
           onPress={onQuote}
           accessibilityRole="button"
-          accessibilityLabel={_(msg`Quote post`)}
+          accessibilityLabel={_(
+            msg({message: `Quote post`, context: 'action'}),
+          )}
           accessibilityHint="">
           <FontAwesomeIcon icon="quote-left" size={24} style={s.blue3} />
           <Text type="title-lg" style={[styles.actionBtnLabel, pal.text]}>
-            <Trans>Quote Post</Trans>
+            <Trans context="action">Quote Post</Trans>
           </Text>
         </TouchableOpacity>
       </View>
diff --git a/src/view/com/modals/SelfLabel.tsx b/src/view/com/modals/SelfLabel.tsx
index 092dd2d32..779a9e71b 100644
--- a/src/view/com/modals/SelfLabel.tsx
+++ b/src/view/com/modals/SelfLabel.tsx
@@ -92,7 +92,7 @@ export function Component({
                   testID="sexualLabelBtn"
                   selected={selected.includes('sexual')}
                   left
-                  label="Suggestive"
+                  label={_(msg`Suggestive`)}
                   onSelect={() => toggleAdultLabel('sexual')}
                   accessibilityHint=""
                   style={s.flex1}
@@ -100,7 +100,7 @@ export function Component({
                 <SelectableBtn
                   testID="nudityLabelBtn"
                   selected={selected.includes('nudity')}
-                  label="Nudity"
+                  label={_(msg`Nudity`)}
                   onSelect={() => toggleAdultLabel('nudity')}
                   accessibilityHint=""
                   style={s.flex1}
@@ -108,7 +108,7 @@ export function Component({
                 <SelectableBtn
                   testID="pornLabelBtn"
                   selected={selected.includes('porn')}
-                  label="Porn"
+                  label={_(msg`Porn`)}
                   right
                   onSelect={() => toggleAdultLabel('porn')}
                   accessibilityHint=""
@@ -154,7 +154,7 @@ export function Component({
           accessibilityLabel={_(msg`Confirm`)}
           accessibilityHint="">
           <Text style={[s.white, s.bold, s.f18]}>
-            <Trans>Done</Trans>
+            <Trans context="action">Done</Trans>
           </Text>
         </TouchableOpacity>
       </View>
diff --git a/src/view/com/modals/ServerInput.tsx b/src/view/com/modals/ServerInput.tsx
index b30293859..550dffa1c 100644
--- a/src/view/com/modals/ServerInput.tsx
+++ b/src/view/com/modals/ServerInput.tsx
@@ -101,7 +101,9 @@ export function Component({onSelect}: {onSelect: (url: string) => void}) {
               onChangeText={setCustomUrl}
               accessibilityLabel={_(msg`Custom domain`)}
               // TODO: Simplify this wording further to be understandable by everyone
-              accessibilityHint="Use your domain as your Bluesky client service provider"
+              accessibilityHint={_(
+                msg`Use your domain as your Bluesky client service provider`,
+              )}
             />
             <TouchableOpacity
               testID="customServerSelectBtn"
@@ -110,7 +112,7 @@ export function Component({onSelect}: {onSelect: (url: string) => void}) {
               accessibilityRole="button"
               accessibilityLabel={`Confirm service. ${
                 customUrl === ''
-                  ? 'Button disabled. Input custom domain to proceed.'
+                  ? _(msg`Button disabled. Input custom domain to proceed.`)
                   : ''
               }`}
               accessibilityHint=""
diff --git a/src/view/com/modals/SwitchAccount.tsx b/src/view/com/modals/SwitchAccount.tsx
index 37691e717..c034c4b52 100644
--- a/src/view/com/modals/SwitchAccount.tsx
+++ b/src/view/com/modals/SwitchAccount.tsx
@@ -62,7 +62,9 @@ function SwitchAccountCard({account}: {account: SessionAccount}) {
           onPress={isSwitchingAccounts ? undefined : onPressSignout}
           accessibilityRole="button"
           accessibilityLabel={_(msg`Sign out`)}
-          accessibilityHint={`Signs ${profile?.displayName} out of Bluesky`}>
+          accessibilityHint={_(
+            msg`Signs ${profile?.displayName} out of Bluesky`,
+          )}>
           <Text type="lg" style={pal.link}>
             <Trans>Sign out</Trans>
           </Text>
@@ -92,8 +94,8 @@ function SwitchAccountCard({account}: {account: SessionAccount}) {
         isSwitchingAccounts ? undefined : () => onPressSwitchAccount(account)
       }
       accessibilityRole="button"
-      accessibilityLabel={`Switch to ${account.handle}`}
-      accessibilityHint="Switches the account you are logged in to">
+      accessibilityLabel={_(msg`Switch to ${account.handle}`)}
+      accessibilityHint={_(msg`Switches the account you are logged in to`)}>
       {contents}
     </TouchableOpacity>
   )
diff --git a/src/view/com/modals/Threadgate.tsx b/src/view/com/modals/Threadgate.tsx
index 0deef185b..0e49fc2f3 100644
--- a/src/view/com/modals/Threadgate.tsx
+++ b/src/view/com/modals/Threadgate.tsx
@@ -126,10 +126,10 @@ export function Component({
           }}
           style={styles.btn}
           accessibilityRole="button"
-          accessibilityLabel={_(msg`Done`)}
+          accessibilityLabel={_(msg({message: `Done`, context: 'action'}))}
           accessibilityHint="">
           <Text style={[s.white, s.bold, s.f18]}>
-            <Trans>Done</Trans>
+            <Trans context="action">Done</Trans>
           </Text>
         </TouchableOpacity>
       </View>
diff --git a/src/view/com/modals/UserAddRemoveLists.tsx b/src/view/com/modals/UserAddRemoveLists.tsx
index 78a3de0b6..23adbe1a8 100644
--- a/src/view/com/modals/UserAddRemoveLists.tsx
+++ b/src/view/com/modals/UserAddRemoveLists.tsx
@@ -76,10 +76,10 @@ export function Component({
           type="default"
           onPress={onPressDone}
           style={styles.footerBtn}
-          accessibilityLabel={_(msg`Done`)}
+          accessibilityLabel={_(msg({message: `Done`, context: 'action'}))}
           accessibilityHint=""
           onAccessibilityEscape={onPressDone}
-          label={_(msg`Done`)}
+          label={_(msg({message: `Done`, context: 'action'}))}
         />
       </View>
     </View>
@@ -175,12 +175,22 @@ function ListItem({
           {sanitizeDisplayName(list.name)}
         </Text>
         <Text type="md" style={[pal.textLight]} numberOfLines={1}>
-          {list.purpose === 'app.bsky.graph.defs#curatelist' && 'User list '}
-          {list.purpose === 'app.bsky.graph.defs#modlist' && 'Moderation list '}
-          by{' '}
-          {list.creator.did === currentAccount?.did
-            ? 'you'
-            : sanitizeHandle(list.creator.handle, '@')}
+          {list.purpose === 'app.bsky.graph.defs#curatelist' &&
+            (list.creator.did === currentAccount?.did ? (
+              <Trans>User list by you</Trans>
+            ) : (
+              <Trans>
+                User list by {sanitizeHandle(list.creator.handle, '@')}
+              </Trans>
+            ))}
+          {list.purpose === 'app.bsky.graph.defs#modlist' &&
+            (list.creator.did === currentAccount?.did ? (
+              <Trans>Moderation list by you</Trans>
+            ) : (
+              <Trans>
+                Moderation list by {sanitizeHandle(list.creator.handle, '@')}
+              </Trans>
+            ))}
         </Text>
       </View>
       <View>
diff --git a/src/view/com/modals/VerifyEmail.tsx b/src/view/com/modals/VerifyEmail.tsx
index 4f2b1aadf..30a57afc5 100644
--- a/src/view/com/modals/VerifyEmail.tsx
+++ b/src/view/com/modals/VerifyEmail.tsx
@@ -75,7 +75,7 @@ export function Component({showReminder}: {showReminder?: boolean}) {
         token: confirmationCode.trim(),
       })
       updateCurrentAccount({emailConfirmed: true})
-      Toast.show('Email verified')
+      Toast.show(_(msg`Email verified`))
       closeModal()
     } catch (e) {
       setError(cleanError(String(e)))
@@ -97,9 +97,15 @@ export function Component({showReminder}: {showReminder?: boolean}) {
         {stage === Stages.Reminder && <ReminderIllustration />}
         <View style={styles.titleSection}>
           <Text type="title-lg" style={[pal.text, styles.title]}>
-            {stage === Stages.Reminder ? 'Please Verify Your Email' : ''}
-            {stage === Stages.ConfirmCode ? 'Enter Confirmation Code' : ''}
-            {stage === Stages.Email ? 'Verify Your Email' : ''}
+            {stage === Stages.Reminder ? (
+              <Trans>Please Verify Your Email</Trans>
+            ) : stage === Stages.Email ? (
+              <Trans>Verify Your Email</Trans>
+            ) : stage === Stages.ConfirmCode ? (
+              <Trans>Enter Confirmation Code</Trans>
+            ) : (
+              ''
+            )}
           </Text>
         </View>
 
@@ -133,7 +139,7 @@ export function Component({showReminder}: {showReminder?: boolean}) {
                 size={16}
               />
               <Text type="xl-medium" style={[pal.text, s.flex1, {minWidth: 0}]}>
-                {currentAccount?.email || '(no email)'}
+                {currentAccount?.email || _(msg`(no email)`)}
               </Text>
             </View>
             <Pressable
@@ -182,7 +188,7 @@ export function Component({showReminder}: {showReminder?: boolean}) {
                   onPress={() => setStage(Stages.Email)}
                   accessibilityLabel={_(msg`Get Started`)}
                   accessibilityHint=""
-                  label="Get Started"
+                  label={_(msg`Get Started`)}
                   labelContainerStyle={{justifyContent: 'center', padding: 4}}
                   labelStyle={[s.f18]}
                 />
@@ -195,7 +201,7 @@ export function Component({showReminder}: {showReminder?: boolean}) {
                     onPress={onSendEmail}
                     accessibilityLabel={_(msg`Send Confirmation Email`)}
                     accessibilityHint=""
-                    label="Send Confirmation Email"
+                    label={_(msg`Send Confirmation Email`)}
                     labelContainerStyle={{
                       justifyContent: 'center',
                       padding: 4,
@@ -207,7 +213,7 @@ export function Component({showReminder}: {showReminder?: boolean}) {
                     type="default"
                     accessibilityLabel={_(msg`I have a code`)}
                     accessibilityHint=""
-                    label="I have a confirmation code"
+                    label={_(msg`I have a confirmation code`)}
                     labelContainerStyle={{
                       justifyContent: 'center',
                       padding: 4,
@@ -224,7 +230,7 @@ export function Component({showReminder}: {showReminder?: boolean}) {
                   onPress={onConfirm}
                   accessibilityLabel={_(msg`Confirm`)}
                   accessibilityHint=""
-                  label="Confirm"
+                  label={_(msg`Confirm`)}
                   labelContainerStyle={{justifyContent: 'center', padding: 4}}
                   labelStyle={[s.f18]}
                 />
@@ -236,10 +242,16 @@ export function Component({showReminder}: {showReminder?: boolean}) {
                   closeModal()
                 }}
                 accessibilityLabel={
-                  stage === Stages.Reminder ? 'Not right now' : 'Cancel'
+                  stage === Stages.Reminder
+                    ? _(msg`Not right now`)
+                    : _(msg`Cancel`)
                 }
                 accessibilityHint=""
-                label={stage === Stages.Reminder ? 'Not right now' : 'Cancel'}
+                label={
+                  stage === Stages.Reminder
+                    ? _(msg`Not right now`)
+                    : _(msg`Cancel`)
+                }
                 labelContainerStyle={{justifyContent: 'center', padding: 4}}
                 labelStyle={[s.f18]}
               />
diff --git a/src/view/com/modals/Waitlist.tsx b/src/view/com/modals/Waitlist.tsx
index a31545c0a..263dd27a2 100644
--- a/src/view/com/modals/Waitlist.tsx
+++ b/src/view/com/modals/Waitlist.tsx
@@ -48,7 +48,7 @@ export function Component({}: {}) {
       } else {
         setError(
           resBody.error ||
-            'Something went wrong. Check your email and try again.',
+            _(msg`Something went wrong. Check your email and try again.`),
         )
       }
     } catch (e: any) {
@@ -75,7 +75,7 @@ export function Component({}: {}) {
         </Text>
         <TextInput
           style={[styles.textInput, pal.borderDark, pal.text, s.mb10, s.mt10]}
-          placeholder="Enter your email"
+          placeholder={_(msg`Enter your email`)}
           placeholderTextColor={pal.textLight.color}
           autoCapitalize="none"
           autoCorrect={false}
@@ -86,7 +86,9 @@ export function Component({}: {}) {
           enterKeyHint="done"
           accessible={true}
           accessibilityLabel={_(msg`Email`)}
-          accessibilityHint="Input your email to get on the Bluesky waitlist"
+          accessibilityHint={_(
+            msg`Input your email to get on the Bluesky waitlist`,
+          )}
         />
         {error ? (
           <View style={s.mt10}>
@@ -114,7 +116,9 @@ export function Component({}: {}) {
             <TouchableOpacity
               onPress={onPressSignup}
               accessibilityRole="button"
-              accessibilityHint={`Confirms signing up ${email} to the waitlist`}>
+              accessibilityHint={_(
+                msg`Confirms signing up ${email} to the waitlist`,
+              )}>
               <LinearGradient
                 colors={[gradients.blueLight.start, gradients.blueLight.end]}
                 start={{x: 0, y: 0}}
@@ -130,7 +134,9 @@ export function Component({}: {}) {
               onPress={onCancel}
               accessibilityRole="button"
               accessibilityLabel={_(msg`Cancel waitlist signup`)}
-              accessibilityHint={`Exits signing up for waitlist with ${email}`}
+              accessibilityHint={_(
+                msg`Exits signing up for waitlist with ${email}`,
+              )}
               onAccessibilityEscape={onCancel}>
               <Text type="button-lg" style={pal.textLight}>
                 <Trans>Cancel</Trans>
diff --git a/src/view/com/notifications/Feed.tsx b/src/view/com/notifications/Feed.tsx
index a99fe2c1d..2088acbac 100644
--- a/src/view/com/notifications/Feed.tsx
+++ b/src/view/com/notifications/Feed.tsx
@@ -13,6 +13,8 @@ import {logger} from '#/logger'
 import {cleanError} from '#/lib/strings/errors'
 import {useModerationOpts} from '#/state/queries/preferences'
 import {List, ListRef} from '../util/List'
+import {useLingui} from '@lingui/react'
+import {msg} from '@lingui/macro'
 
 const EMPTY_FEED_ITEM = {_reactKey: '__empty__'}
 const LOAD_MORE_ERROR_ITEM = {_reactKey: '__load_more_error__'}
@@ -31,6 +33,7 @@ export function Feed({
 }) {
   const [isPTRing, setIsPTRing] = React.useState(false)
 
+  const {_} = useLingui()
   const moderationOpts = useModerationOpts()
   const {checkUnread} = useUnreadNotificationsApi()
   const {
@@ -101,14 +104,16 @@ export function Feed({
         return (
           <EmptyState
             icon="bell"
-            message="No notifications yet!"
+            message={_(msg`No notifications yet!`)}
             style={styles.emptyState}
           />
         )
       } else if (item === LOAD_MORE_ERROR_ITEM) {
         return (
           <LoadMoreRetryBtn
-            label="There was an issue fetching notifications. Tap here to try again."
+            label={_(
+              msg`There was an issue fetching notifications. Tap here to try again.`,
+            )}
             onPress={onPressRetryLoadMore}
           />
         )
@@ -117,7 +122,7 @@ export function Feed({
       }
       return <FeedItem item={item} moderationOpts={moderationOpts!} />
     },
-    [onPressRetryLoadMore, moderationOpts],
+    [onPressRetryLoadMore, moderationOpts, _],
   )
 
   const FeedFooter = React.useCallback(
diff --git a/src/view/com/notifications/FeedItem.tsx b/src/view/com/notifications/FeedItem.tsx
index 24b7e4fb6..e9d8b63e2 100644
--- a/src/view/com/notifications/FeedItem.tsx
+++ b/src/view/com/notifications/FeedItem.tsx
@@ -65,6 +65,7 @@ let FeedItem = ({
   moderationOpts: ModerationOpts
 }): React.ReactNode => {
   const pal = usePalette('default')
+  const {_} = useLingui()
   const [isAuthorsExpanded, setAuthorsExpanded] = useState<boolean>(false)
   const itemHref = useMemo(() => {
     if (item.type === 'post-like' || item.type === 'repost') {
@@ -151,24 +152,26 @@ let FeedItem = ({
   let icon: Props['icon'] | 'HeartIconSolid'
   let iconStyle: Props['style'] = []
   if (item.type === 'post-like') {
-    action = 'liked your post'
+    action = _(msg`liked your post`)
     icon = 'HeartIconSolid'
     iconStyle = [
       s.likeColor as FontAwesomeIconStyle,
       {position: 'relative', top: -4},
     ]
   } else if (item.type === 'repost') {
-    action = 'reposted your post'
+    action = _(msg`reposted your post`)
     icon = 'retweet'
     iconStyle = [s.green3 as FontAwesomeIconStyle]
   } else if (item.type === 'follow') {
-    action = 'followed you'
+    action = _(msg`followed you`)
     icon = 'user-plus'
     iconStyle = [s.blue3 as FontAwesomeIconStyle]
   } else if (item.type === 'feedgen-like') {
-    action = `liked your custom feed${
-      item.subjectUri ? ` '${new AtUri(item.subjectUri).rkey}'` : ''
-    }`
+    action = _(
+      msg`liked your custom feed${
+        item.subjectUri ? ` '${new AtUri(item.subjectUri).rkey}'` : ''
+      }`,
+    )
     icon = 'HeartIconSolid'
     iconStyle = [
       s.likeColor as FontAwesomeIconStyle,
@@ -314,14 +317,16 @@ function CondensedAuthorsList({
           onPress={onToggleAuthorsExpanded}
           accessibilityRole="button"
           accessibilityLabel={_(msg`Hide user list`)}
-          accessibilityHint="Collapses list of users for a given notification">
+          accessibilityHint={_(
+            msg`Collapses list of users for a given notification`,
+          )}>
           <FontAwesomeIcon
             icon="angle-up"
             size={18}
             style={[styles.expandedAuthorsCloseBtnIcon, pal.text]}
           />
           <Text type="sm-medium" style={pal.text}>
-            <Trans>Hide</Trans>
+            <Trans context="action">Hide</Trans>
           </Text>
         </TouchableOpacity>
       </View>
@@ -343,7 +348,9 @@ function CondensedAuthorsList({
   return (
     <TouchableOpacity
       accessibilityLabel={_(msg`Show users`)}
-      accessibilityHint="Opens an expanded list of users in this notification"
+      accessibilityHint={_(
+        msg`Opens an expanded list of users in this notification`,
+      )}
       onPress={onToggleAuthorsExpanded}>
       <View style={styles.avis}>
         {authors.slice(0, MAX_AUTHORS).map(author => (
diff --git a/src/view/com/pager/FeedsTabBarMobile.tsx b/src/view/com/pager/FeedsTabBarMobile.tsx
index 024f9bfab..2c5ba5dfb 100644
--- a/src/view/com/pager/FeedsTabBarMobile.tsx
+++ b/src/view/com/pager/FeedsTabBarMobile.tsx
@@ -74,7 +74,9 @@ export function FeedsTabBar(
             onPress={onPressAvi}
             accessibilityRole="button"
             accessibilityLabel={_(msg`Open navigation`)}
-            accessibilityHint="Access profile and other navigation links"
+            accessibilityHint={_(
+              msg`Access profile and other navigation links`,
+            )}
             hitSlop={HITSLOP_10}>
             <FontAwesomeIcon
               icon="bars"
diff --git a/src/view/com/post-thread/PostThread.tsx b/src/view/com/post-thread/PostThread.tsx
index 6cd1f3551..cb7fd3f41 100644
--- a/src/view/com/post-thread/PostThread.tsx
+++ b/src/view/com/post-thread/PostThread.tsx
@@ -222,7 +222,11 @@ function PostThreadLoaded({
   const renderItem = React.useCallback(
     ({item, index}: {item: YieldedItem; index: number}) => {
       if (item === TOP_COMPONENT) {
-        return isTablet ? <ViewHeader title={_(msg`Post`)} /> : null
+        return isTablet ? (
+          <ViewHeader
+            title={_(msg({message: `Post`, context: 'description'}))}
+          />
+        ) : null
       } else if (item === PARENT_SPINNER) {
         return (
           <View style={styles.parentSpinner}>
@@ -393,7 +397,7 @@ function PostThreadBlocked() {
               style={[pal.link as FontAwesomeIconStyle, s.mr5]}
               size={14}
             />
-            Back
+            <Trans context="action">Back</Trans>
           </Text>
         </TouchableOpacity>
       </View>
diff --git a/src/view/com/post-thread/PostThreadItem.tsx b/src/view/com/post-thread/PostThreadItem.tsx
index fc03c0d95..bb3c7e2cc 100644
--- a/src/view/com/post-thread/PostThreadItem.tsx
+++ b/src/view/com/post-thread/PostThreadItem.tsx
@@ -158,6 +158,7 @@ let PostThreadItemLoaded = ({
   onPostReply: () => void
 }): React.ReactNode => {
   const pal = usePalette('default')
+  const {_} = useLingui()
   const langPrefs = useLanguagePrefs()
   const {openComposer} = useComposerControls()
   const {currentAccount} = useSession()
@@ -172,7 +173,7 @@ let PostThreadItemLoaded = ({
     const urip = new AtUri(post.uri)
     return makeProfileLink(post.author, 'post', urip.rkey)
   }, [post.uri, post.author])
-  const itemTitle = `Post by ${post.author.handle}`
+  const itemTitle = _(msg`Post by ${post.author.handle}`)
   const authorHref = makeProfileLink(post.author)
   const authorTitle = post.author.handle
   const isAuthorMuted = post.author.viewer?.muted
@@ -180,12 +181,12 @@ let PostThreadItemLoaded = ({
     const urip = new AtUri(post.uri)
     return makeProfileLink(post.author, 'post', urip.rkey, 'liked-by')
   }, [post.uri, post.author])
-  const likesTitle = 'Likes on this post'
+  const likesTitle = _(msg`Likes on this post`)
   const repostsHref = React.useMemo(() => {
     const urip = new AtUri(post.uri)
     return makeProfileLink(post.author, 'post', urip.rkey, 'reposted-by')
   }, [post.uri, post.author])
-  const repostsTitle = 'Reposts of this post'
+  const repostsTitle = _(msg`Reposts of this post`)
   const isModeratedPost =
     moderation.decisions.post.cause?.type === 'label' &&
     moderation.decisions.post.cause.label.src !== currentAccount?.did
@@ -225,7 +226,7 @@ let PostThreadItemLoaded = ({
   }, [setLimitLines])
 
   if (!record) {
-    return <ErrorMessage message="Invalid or unsupported post record" />
+    return <ErrorMessage message={_(msg`Invalid or unsupported post record`)} />
   }
 
   if (isHighlightedPost) {
@@ -563,7 +564,7 @@ let PostThreadItemLoaded = ({
                 ) : undefined}
                 {limitLines ? (
                   <TextLink
-                    text="Show More"
+                    text={_(msg`Show More`)}
                     style={pal.link}
                     onPress={onPressShowMore}
                     href="#"
diff --git a/src/view/com/post/Post.tsx b/src/view/com/post/Post.tsx
index ac4689d2f..0e5a459fa 100644
--- a/src/view/com/post/Post.tsx
+++ b/src/view/com/post/Post.tsx
@@ -27,6 +27,8 @@ import {countLines} from 'lib/strings/helpers'
 import {useModerationOpts} from '#/state/queries/preferences'
 import {useComposerControls} from '#/state/shell/composer'
 import {Shadow, usePostShadow, POST_TOMBSTONE} from '#/state/cache/post-shadow'
+import {Trans, msg} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
 
 export function Post({
   post,
@@ -95,6 +97,7 @@ function PostInner({
   style?: StyleProp<ViewStyle>
 }) {
   const pal = usePalette('default')
+  const {_} = useLingui()
   const {openComposer} = useComposerControls()
   const [limitLines, setLimitLines] = useState(
     () => countLines(richText?.text) >= MAX_POST_LINES,
@@ -159,13 +162,15 @@ function PostInner({
                 style={[pal.textLight, s.mr2]}
                 lineHeight={1.2}
                 numberOfLines={1}>
-                Reply to{' '}
-                <UserInfoText
-                  type="sm"
-                  did={replyAuthorDid}
-                  attr="displayName"
-                  style={[pal.textLight]}
-                />
+                <Trans context="description">
+                  Reply to{' '}
+                  <UserInfoText
+                    type="sm"
+                    did={replyAuthorDid}
+                    attr="displayName"
+                    style={[pal.textLight]}
+                  />
+                </Trans>
               </Text>
             </View>
           )}
@@ -188,7 +193,7 @@ function PostInner({
             ) : undefined}
             {limitLines ? (
               <TextLink
-                text="Show More"
+                text={_(msg`Show More`)}
                 style={pal.link}
                 onPress={onPressShowMore}
                 href="#"
diff --git a/src/view/com/posts/CustomFeedEmptyState.tsx b/src/view/com/posts/CustomFeedEmptyState.tsx
index e83a94f03..62a10fd19 100644
--- a/src/view/com/posts/CustomFeedEmptyState.tsx
+++ b/src/view/com/posts/CustomFeedEmptyState.tsx
@@ -12,6 +12,7 @@ import {NavigationProp} from 'lib/routes/types'
 import {usePalette} from 'lib/hooks/usePalette'
 import {s} from 'lib/styles'
 import {isWeb} from 'platform/detection'
+import {Trans} from '@lingui/macro'
 
 export function CustomFeedEmptyState() {
   const pal = usePalette('default')
@@ -33,15 +34,17 @@ export function CustomFeedEmptyState() {
         <MagnifyingGlassIcon style={[styles.emptyIcon, pal.text]} size={62} />
       </View>
       <Text type="xl-medium" style={[s.textCenter, pal.text]}>
-        This feed is empty! You may need to follow more users or tune your
-        language settings.
+        <Trans>
+          This feed is empty! You may need to follow more users or tune your
+          language settings.
+        </Trans>
       </Text>
       <Button
         type="inverted"
         style={styles.emptyBtn}
         onPress={onPressFindAccounts}>
         <Text type="lg-medium" style={palInverted.text}>
-          Find accounts to follow
+          <Trans>Find accounts to follow</Trans>
         </Text>
         <FontAwesomeIcon
           icon="angle-right"
diff --git a/src/view/com/posts/Feed.tsx b/src/view/com/posts/Feed.tsx
index 02a3537eb..6b6ad6e92 100644
--- a/src/view/com/posts/Feed.tsx
+++ b/src/view/com/posts/Feed.tsx
@@ -28,6 +28,8 @@ import {isWeb} from '#/platform/detection'
 import {listenPostCreated} from '#/state/events'
 import {useSession} from '#/state/session'
 import {STALE} from '#/state/queries'
+import {msg} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
 
 const LOADING_ITEM = {_reactKey: '__loading__'}
 const EMPTY_FEED_ITEM = {_reactKey: '__empty__'}
@@ -74,6 +76,7 @@ let Feed = ({
 }): React.ReactNode => {
   const theme = useTheme()
   const {track} = useAnalytics()
+  const {_} = useLingui()
   const queryClient = useQueryClient()
   const {currentAccount} = useSession()
   const [isPTRing, setIsPTRing] = React.useState(false)
@@ -250,7 +253,9 @@ let Feed = ({
       } else if (item === LOAD_MORE_ERROR_ITEM) {
         return (
           <LoadMoreRetryBtn
-            label="There was an issue fetching posts. Tap here to try again."
+            label={_(
+              msg`There was an issue fetching posts. Tap here to try again.`,
+            )}
             onPress={onPressRetryLoadMore}
           />
         )
@@ -259,7 +264,7 @@ let Feed = ({
       }
       return <FeedSlice slice={item} />
     },
-    [feed, error, onPressTryAgain, onPressRetryLoadMore, renderEmptyState],
+    [feed, error, onPressTryAgain, onPressRetryLoadMore, renderEmptyState, _],
   )
 
   const shouldRenderEndOfFeed =
diff --git a/src/view/com/posts/FeedErrorMessage.tsx b/src/view/com/posts/FeedErrorMessage.tsx
index aeac45980..48ed49bb1 100644
--- a/src/view/com/posts/FeedErrorMessage.tsx
+++ b/src/view/com/posts/FeedErrorMessage.tsx
@@ -38,6 +38,7 @@ export function FeedErrorMessage({
   error?: Error
   onPressTryAgain: () => void
 }) {
+  const {_: _l} = useLingui()
   const knownError = React.useMemo(
     () => detectKnownError(feedDesc, error),
     [feedDesc, error],
@@ -60,7 +61,7 @@ export function FeedErrorMessage({
     return (
       <EmptyState
         icon="ban"
-        message="Posts hidden"
+        message={_l(msgLingui`Posts hidden`)}
         style={{paddingVertical: 40}}
       />
     )
@@ -134,7 +135,9 @@ function FeedgenErrorMessage({
           await removeFeed({uri})
         } catch (err) {
           Toast.show(
-            'There was an an issue removing this feed. Please check your internet connection and try again.',
+            _l(
+              msgLingui`There was an an issue removing this feed. Please check your internet connection and try again.`,
+            ),
           )
           logger.error('Failed to remove feed', {error: err})
         }
@@ -160,20 +163,20 @@ function FeedgenErrorMessage({
             {knownError === KnownError.FeedgenDoesNotExist && (
               <Button
                 type="inverted"
-                label="Remove feed"
+                label={_l(msgLingui`Remove feed`)}
                 onPress={onRemoveFeed}
               />
             )}
             <Button
               type="default-light"
-              label="View profile"
+              label={_l(msgLingui`View profile`)}
               onPress={onViewProfile}
             />
           </View>
         )
       }
     }
-  }, [knownError, onViewProfile, onRemoveFeed])
+  }, [knownError, onViewProfile, onRemoveFeed, _l])
 
   return (
     <View
@@ -191,7 +194,7 @@ function FeedgenErrorMessage({
 
       {rawError?.message && (
         <Text style={pal.textLight}>
-          <Trans>Message from server</Trans>: {rawError.message}
+          <Trans>Message from server: {rawError.message}</Trans>
         </Text>
       )}
 
diff --git a/src/view/com/posts/FeedItem.tsx b/src/view/com/posts/FeedItem.tsx
index 2a5abcd68..f2b5605dd 100644
--- a/src/view/com/posts/FeedItem.tsx
+++ b/src/view/com/posts/FeedItem.tsx
@@ -35,6 +35,8 @@ import {useComposerControls} from '#/state/shell/composer'
 import {Shadow, usePostShadow, POST_TOMBSTONE} from '#/state/cache/post-shadow'
 import {FeedNameText} from '../util/FeedInfoText'
 import {useSession} from '#/state/session'
+import {Trans, msg} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
 
 export function FeedItem({
   post,
@@ -103,6 +105,7 @@ let FeedItemInner = ({
 }): React.ReactNode => {
   const {openComposer} = useComposerControls()
   const pal = usePalette('default')
+  const {_} = useLingui()
   const {currentAccount} = useSession()
   const href = useMemo(() => {
     const urip = new AtUri(post.uri)
@@ -182,24 +185,28 @@ let FeedItemInner = ({
                 style={pal.textLight}
                 lineHeight={1.2}
                 numberOfLines={1}>
-                From{' '}
-                <FeedNameText
-                  type="sm-bold"
-                  uri={reason.uri}
-                  href={reason.href}
-                  lineHeight={1.2}
-                  numberOfLines={1}
-                  style={pal.textLight}
-                />
+                <Trans context="from-feed">
+                  From{' '}
+                  <FeedNameText
+                    type="sm-bold"
+                    uri={reason.uri}
+                    href={reason.href}
+                    lineHeight={1.2}
+                    numberOfLines={1}
+                    style={pal.textLight}
+                  />
+                </Trans>
               </Text>
             </Link>
           ) : AppBskyFeedDefs.isReasonRepost(reason) ? (
             <Link
               style={styles.includeReason}
               href={makeProfileLink(reason.by)}
-              title={`Reposted by ${sanitizeDisplayName(
-                reason.by.displayName || reason.by.handle,
-              )}`}>
+              title={_(
+                msg`Reposted by ${sanitizeDisplayName(
+                  reason.by.displayName || reason.by.handle,
+                )})`,
+              )}>
               <FontAwesomeIcon
                 icon="retweet"
                 style={{
@@ -213,17 +220,19 @@ let FeedItemInner = ({
                 style={pal.textLight}
                 lineHeight={1.2}
                 numberOfLines={1}>
-                Reposted by{' '}
-                <TextLinkOnWebOnly
-                  type="sm-bold"
-                  style={pal.textLight}
-                  lineHeight={1.2}
-                  numberOfLines={1}
-                  text={sanitizeDisplayName(
-                    reason.by.displayName || sanitizeHandle(reason.by.handle),
-                  )}
-                  href={makeProfileLink(reason.by)}
-                />
+                <Trans>
+                  Reposted by{' '}
+                  <TextLinkOnWebOnly
+                    type="sm-bold"
+                    style={pal.textLight}
+                    lineHeight={1.2}
+                    numberOfLines={1}
+                    text={sanitizeDisplayName(
+                      reason.by.displayName || sanitizeHandle(reason.by.handle),
+                    )}
+                    href={makeProfileLink(reason.by)}
+                  />
+                </Trans>
               </Text>
             </Link>
           ) : null}
@@ -274,13 +283,15 @@ let FeedItemInner = ({
                 style={[pal.textLight, s.mr2]}
                 lineHeight={1.2}
                 numberOfLines={1}>
-                Reply to{' '}
-                <UserInfoText
-                  type="md"
-                  did={replyAuthorDid}
-                  attr="displayName"
-                  style={[pal.textLight, s.ml2]}
-                />
+                <Trans context="description">
+                  Reply to{' '}
+                  <UserInfoText
+                    type="md"
+                    did={replyAuthorDid}
+                    attr="displayName"
+                    style={[pal.textLight, s.ml2]}
+                  />
+                </Trans>
               </Text>
             </View>
           )}
@@ -317,6 +328,7 @@ let PostContent = ({
   postAuthor: AppBskyFeedDefs.PostView['author']
 }): React.ReactNode => {
   const pal = usePalette('default')
+  const {_} = useLingui()
   const [limitLines, setLimitLines] = useState(
     () => countLines(richText.text) >= MAX_POST_LINES,
   )
@@ -346,7 +358,7 @@ let PostContent = ({
       ) : undefined}
       {limitLines ? (
         <TextLink
-          text="Show More"
+          text={_(msg`Show More`)}
           style={pal.link}
           onPress={onPressShowMore}
           href="#"
diff --git a/src/view/com/posts/FeedSlice.tsx b/src/view/com/posts/FeedSlice.tsx
index c1a8c0e18..84edee4a1 100644
--- a/src/view/com/posts/FeedSlice.tsx
+++ b/src/view/com/posts/FeedSlice.tsx
@@ -8,6 +8,7 @@ import Svg, {Circle, Line} from 'react-native-svg'
 import {FeedItem} from './FeedItem'
 import {usePalette} from 'lib/hooks/usePalette'
 import {makeProfileLink} from 'lib/routes/links'
+import {Trans} from '@lingui/macro'
 
 let FeedSlice = ({slice}: {slice: FeedPostSlice}): React.ReactNode => {
   if (slice.isThread && slice.items.length > 3) {
@@ -99,7 +100,7 @@ function ViewFullThread({slice}: {slice: FeedPostSlice}) {
       </View>
 
       <Text type="md" style={[pal.link, {paddingTop: 18, paddingBottom: 4}]}>
-        View full thread
+        <Trans>View full thread</Trans>
       </Text>
     </Link>
   )
diff --git a/src/view/com/posts/FollowingEmptyState.tsx b/src/view/com/posts/FollowingEmptyState.tsx
index aac29603d..ef02039af 100644
--- a/src/view/com/posts/FollowingEmptyState.tsx
+++ b/src/view/com/posts/FollowingEmptyState.tsx
@@ -12,6 +12,7 @@ import {NavigationProp} from 'lib/routes/types'
 import {usePalette} from 'lib/hooks/usePalette'
 import {s} from 'lib/styles'
 import {isWeb} from 'platform/detection'
+import {Trans} from '@lingui/macro'
 
 export function FollowingEmptyState() {
   const pal = usePalette('default')
@@ -43,15 +44,17 @@ export function FollowingEmptyState() {
           <MagnifyingGlassIcon style={[styles.icon, pal.text]} size={62} />
         </View>
         <Text type="xl-medium" style={[s.textCenter, pal.text]}>
-          Your following feed is empty! Follow more users to see what's
-          happening.
+          <Trans>
+            Your following feed is empty! Follow more users to see what's
+            happening.
+          </Trans>
         </Text>
         <Button
           type="inverted"
           style={styles.emptyBtn}
           onPress={onPressFindAccounts}>
           <Text type="lg-medium" style={palInverted.text}>
-            Find accounts to follow
+            <Trans>Find accounts to follow</Trans>
           </Text>
           <FontAwesomeIcon
             icon="angle-right"
@@ -61,14 +64,14 @@ export function FollowingEmptyState() {
         </Button>
 
         <Text type="xl-medium" style={[s.textCenter, pal.text, s.mt20]}>
-          You can also discover new Custom Feeds to follow.
+          <Trans>You can also discover new Custom Feeds to follow.</Trans>
         </Text>
         <Button
           type="inverted"
           style={[styles.emptyBtn, s.mt10]}
           onPress={onPressDiscoverFeeds}>
           <Text type="lg-medium" style={palInverted.text}>
-            Discover new custom feeds
+            <Trans>Discover new custom feeds</Trans>
           </Text>
           <FontAwesomeIcon
             icon="angle-right"
diff --git a/src/view/com/posts/FollowingEndOfFeed.tsx b/src/view/com/posts/FollowingEndOfFeed.tsx
index 3f1297547..bea5bedea 100644
--- a/src/view/com/posts/FollowingEndOfFeed.tsx
+++ b/src/view/com/posts/FollowingEndOfFeed.tsx
@@ -11,6 +11,7 @@ import {NavigationProp} from 'lib/routes/types'
 import {usePalette} from 'lib/hooks/usePalette'
 import {s} from 'lib/styles'
 import {isWeb} from 'platform/detection'
+import {Trans} from '@lingui/macro'
 
 export function FollowingEndOfFeed() {
   const pal = usePalette('default')
@@ -44,15 +45,17 @@ export function FollowingEndOfFeed() {
       ]}>
       <View style={styles.inner}>
         <Text type="xl-medium" style={[s.textCenter, pal.text]}>
-          You've reached the end of your feed! Find some more accounts to
-          follow.
+          <Trans>
+            You've reached the end of your feed! Find some more accounts to
+            follow.
+          </Trans>
         </Text>
         <Button
           type="inverted"
           style={styles.emptyBtn}
           onPress={onPressFindAccounts}>
           <Text type="lg-medium" style={palInverted.text}>
-            Find accounts to follow
+            <Trans>Find accounts to follow</Trans>
           </Text>
           <FontAwesomeIcon
             icon="angle-right"
@@ -62,14 +65,14 @@ export function FollowingEndOfFeed() {
         </Button>
 
         <Text type="xl-medium" style={[s.textCenter, pal.text, s.mt20]}>
-          You can also discover new Custom Feeds to follow.
+          <Trans>You can also discover new Custom Feeds to follow.</Trans>
         </Text>
         <Button
           type="inverted"
           style={[styles.emptyBtn, s.mt10]}
           onPress={onPressDiscoverFeeds}>
           <Text type="lg-medium" style={palInverted.text}>
-            Discover new custom feeds
+            <Trans>Discover new custom feeds</Trans>
           </Text>
           <FontAwesomeIcon
             icon="angle-right"
diff --git a/src/view/com/profile/FollowButton.tsx b/src/view/com/profile/FollowButton.tsx
index 1252f8ca8..9cc635b66 100644
--- a/src/view/com/profile/FollowButton.tsx
+++ b/src/view/com/profile/FollowButton.tsx
@@ -5,6 +5,8 @@ import {Button, ButtonType} from '../util/forms/Button'
 import * as Toast from '../util/Toast'
 import {useProfileFollowMutationQueue} from '#/state/queries/profile'
 import {Shadow} from '#/state/cache/types'
+import {useLingui} from '@lingui/react'
+import {msg} from '@lingui/macro'
 
 export function FollowButton({
   unfollowedType = 'inverted',
@@ -18,13 +20,14 @@ export function FollowButton({
   labelStyle?: StyleProp<TextStyle>
 }) {
   const [queueFollow, queueUnfollow] = useProfileFollowMutationQueue(profile)
+  const {_} = useLingui()
 
   const onPressFollow = async () => {
     try {
       await queueFollow()
     } catch (e: any) {
       if (e?.name !== 'AbortError') {
-        Toast.show(`An issue occurred, please try again.`)
+        Toast.show(_(msg`An issue occurred, please try again.`))
       }
     }
   }
@@ -34,7 +37,7 @@ export function FollowButton({
       await queueUnfollow()
     } catch (e: any) {
       if (e?.name !== 'AbortError') {
-        Toast.show(`An issue occurred, please try again.`)
+        Toast.show(_(msg`An issue occurred, please try again.`))
       }
     }
   }
@@ -49,7 +52,7 @@ export function FollowButton({
         type={followedType}
         labelStyle={labelStyle}
         onPress={onPressUnfollow}
-        label="Unfollow"
+        label={_(msg({message: 'Unfollow', context: 'action'}))}
       />
     )
   } else {
@@ -58,7 +61,7 @@ export function FollowButton({
         type={unfollowedType}
         labelStyle={labelStyle}
         onPress={onPressFollow}
-        label="Follow"
+        label={_(msg({message: 'Follow', context: 'action'}))}
       />
     )
   }
diff --git a/src/view/com/profile/ProfileCard.tsx b/src/view/com/profile/ProfileCard.tsx
index ef95f5924..266adc51d 100644
--- a/src/view/com/profile/ProfileCard.tsx
+++ b/src/view/com/profile/ProfileCard.tsx
@@ -23,6 +23,7 @@ import {Shadow} from '#/state/cache/types'
 import {useModerationOpts} from '#/state/queries/preferences'
 import {useProfileShadow} from '#/state/cache/profile-shadow'
 import {useSession} from '#/state/session'
+import {Trans} from '@lingui/macro'
 
 export function ProfileCard({
   testID,
@@ -137,7 +138,7 @@ function ProfileCardPills({
       {followedBy && (
         <View style={[s.mt5, pal.btn, styles.pill]}>
           <Text type="xs" style={pal.text}>
-            Follows You
+            <Trans>Follows You</Trans>
           </Text>
         </View>
       )}
@@ -190,8 +191,10 @@ function FollowersList({
         style={[styles.followsByDesc, pal.textLight]}
         numberOfLines={2}
         lineHeight={1.2}>
-        Followed by{' '}
-        {followersWithMods.map(({f}) => f.displayName || f.handle).join(', ')}
+        <Trans>
+          Followed by{' '}
+          {followersWithMods.map(({f}) => f.displayName || f.handle).join(', ')}
+        </Trans>
       </Text>
       {followersWithMods.slice(0, 3).map(({f, mod}) => (
         <View key={f.did} style={styles.followedByAviContainer}>
diff --git a/src/view/com/profile/ProfileHeader.tsx b/src/view/com/profile/ProfileHeader.tsx
index 7d52216b0..d831ad777 100644
--- a/src/view/com/profile/ProfileHeader.tsx
+++ b/src/view/com/profile/ProfileHeader.tsx
@@ -192,14 +192,16 @@ let ProfileHeaderLoaded = ({
         track('ProfileHeader:FollowButtonClicked')
         await queueFollow()
         Toast.show(
-          `Following ${sanitizeDisplayName(
-            profile.displayName || profile.handle,
-          )}`,
+          _(
+            msg`Following ${sanitizeDisplayName(
+              profile.displayName || profile.handle,
+            )}`,
+          ),
         )
       } catch (e: any) {
         if (e?.name !== 'AbortError') {
           logger.error('Failed to follow', {error: String(e)})
-          Toast.show(`There was an issue! ${e.toString()}`)
+          Toast.show(_(msg`There was an issue! ${e.toString()}`))
         }
       }
     })
@@ -211,14 +213,16 @@ let ProfileHeaderLoaded = ({
         track('ProfileHeader:UnfollowButtonClicked')
         await queueUnfollow()
         Toast.show(
-          `No longer following ${sanitizeDisplayName(
-            profile.displayName || profile.handle,
-          )}`,
+          _(
+            msg`No longer following ${sanitizeDisplayName(
+              profile.displayName || profile.handle,
+            )}`,
+          ),
         )
       } catch (e: any) {
         if (e?.name !== 'AbortError') {
           logger.error('Failed to unfollow', {error: String(e)})
-          Toast.show(`There was an issue! ${e.toString()}`)
+          Toast.show(_(msg`There was an issue! ${e.toString()}`))
         }
       }
     })
@@ -253,27 +257,27 @@ let ProfileHeaderLoaded = ({
     track('ProfileHeader:MuteAccountButtonClicked')
     try {
       await queueMute()
-      Toast.show('Account muted')
+      Toast.show(_(msg`Account muted`))
     } catch (e: any) {
       if (e?.name !== 'AbortError') {
         logger.error('Failed to mute account', {error: e})
-        Toast.show(`There was an issue! ${e.toString()}`)
+        Toast.show(_(msg`There was an issue! ${e.toString()}`))
       }
     }
-  }, [track, queueMute])
+  }, [track, queueMute, _])
 
   const onPressUnmuteAccount = React.useCallback(async () => {
     track('ProfileHeader:UnmuteAccountButtonClicked')
     try {
       await queueUnmute()
-      Toast.show('Account unmuted')
+      Toast.show(_(msg`Account unmuted`))
     } catch (e: any) {
       if (e?.name !== 'AbortError') {
         logger.error('Failed to unmute account', {error: e})
-        Toast.show(`There was an issue! ${e.toString()}`)
+        Toast.show(_(msg`There was an issue! ${e.toString()}`))
       }
     }
-  }, [track, queueUnmute])
+  }, [track, queueUnmute, _])
 
   const onPressBlockAccount = React.useCallback(async () => {
     track('ProfileHeader:BlockAccountButtonClicked')
@@ -286,11 +290,11 @@ let ProfileHeaderLoaded = ({
       onPressConfirm: async () => {
         try {
           await queueBlock()
-          Toast.show('Account blocked')
+          Toast.show(_(msg`Account blocked`))
         } catch (e: any) {
           if (e?.name !== 'AbortError') {
             logger.error('Failed to block account', {error: e})
-            Toast.show(`There was an issue! ${e.toString()}`)
+            Toast.show(_(msg`There was an issue! ${e.toString()}`))
           }
         }
       },
@@ -308,11 +312,11 @@ let ProfileHeaderLoaded = ({
       onPressConfirm: async () => {
         try {
           await queueUnblock()
-          Toast.show('Account unblocked')
+          Toast.show(_(msg`Account unblocked`))
         } catch (e: any) {
           if (e?.name !== 'AbortError') {
             logger.error('Failed to unblock account', {error: e})
-            Toast.show(`There was an issue! ${e.toString()}`)
+            Toast.show(_(msg`There was an issue! ${e.toString()}`))
           }
         }
       },
@@ -451,7 +455,9 @@ let ProfileHeaderLoaded = ({
               style={[styles.btn, styles.mainBtn, pal.btn]}
               accessibilityRole="button"
               accessibilityLabel={_(msg`Edit profile`)}
-              accessibilityHint="Opens editor for profile display name, avatar, background image, and description">
+              accessibilityHint={_(
+                msg`Opens editor for profile display name, avatar, background image, and description`,
+              )}>
               <Text type="button" style={pal.text}>
                 <Trans>Edit Profile</Trans>
               </Text>
@@ -466,7 +472,7 @@ let ProfileHeaderLoaded = ({
                 accessibilityLabel={_(msg`Unblock`)}
                 accessibilityHint="">
                 <Text type="button" style={[pal.text, s.bold]}>
-                  <Trans>Unblock</Trans>
+                  <Trans context="action">Unblock</Trans>
                 </Text>
               </TouchableOpacity>
             )
@@ -488,8 +494,12 @@ let ProfileHeaderLoaded = ({
                     },
                   ]}
                   accessibilityRole="button"
-                  accessibilityLabel={`Show follows similar to ${profile.handle}`}
-                  accessibilityHint={`Shows a list of users similar to this user.`}>
+                  accessibilityLabel={_(
+                    msg`Show follows similar to ${profile.handle}`,
+                  )}
+                  accessibilityHint={_(
+                    msg`Shows a list of users similar to this user.`,
+                  )}>
                   <FontAwesomeIcon
                     icon="user-plus"
                     style={[
@@ -511,8 +521,10 @@ let ProfileHeaderLoaded = ({
                   onPress={onPressUnfollow}
                   style={[styles.btn, styles.mainBtn, pal.btn]}
                   accessibilityRole="button"
-                  accessibilityLabel={`Unfollow ${profile.handle}`}
-                  accessibilityHint={`Hides posts from ${profile.handle} in your feed`}>
+                  accessibilityLabel={_(msg`Unfollow ${profile.handle}`)}
+                  accessibilityHint={_(
+                    msg`Hides posts from ${profile.handle} in your feed`,
+                  )}>
                   <FontAwesomeIcon
                     icon="check"
                     style={[pal.text, s.mr5]}
@@ -528,8 +540,10 @@ let ProfileHeaderLoaded = ({
                   onPress={onPressFollow}
                   style={[styles.btn, styles.mainBtn, palInverted.view]}
                   accessibilityRole="button"
-                  accessibilityLabel={`Follow ${profile.handle}`}
-                  accessibilityHint={`Shows posts from ${profile.handle} in your feed`}>
+                  accessibilityLabel={_(msg`Follow ${profile.handle}`)}
+                  accessibilityHint={_(
+                    msg`Shows posts from ${profile.handle} in your feed`,
+                  )}>
                   <FontAwesomeIcon
                     icon="plus"
                     style={[palInverted.text, s.mr5]}
@@ -580,7 +594,7 @@ let ProfileHeaderLoaded = ({
               invalidHandle ? styles.invalidHandle : undefined,
               styles.handle,
             ]}>
-            {invalidHandle ? 'âš Invalid Handle' : `@${profile.handle}`}
+            {invalidHandle ? _(msg`âš Invalid Handle`) : `@${profile.handle}`}
           </ThemedText>
         </View>
         {!blockHide && (
@@ -597,7 +611,7 @@ let ProfileHeaderLoaded = ({
                 }
                 asAnchor
                 accessibilityLabel={`${followers} ${pluralizedFollowers}`}
-                accessibilityHint={'Opens followers list'}>
+                accessibilityHint={_(msg`Opens followers list`)}>
                 <Text type="md" style={[s.bold, pal.text]}>
                   {followers}{' '}
                 </Text>
@@ -615,14 +629,16 @@ let ProfileHeaderLoaded = ({
                   })
                 }
                 asAnchor
-                accessibilityLabel={`${following} following`}
-                accessibilityHint={'Opens following list'}>
-                <Text type="md" style={[s.bold, pal.text]}>
-                  {following}{' '}
-                </Text>
-                <Text type="md" style={[pal.textLight]}>
-                  <Trans>following</Trans>
-                </Text>
+                accessibilityLabel={_(msg`${following} following`)}
+                accessibilityHint={_(msg`Opens following list`)}>
+                <Trans>
+                  <Text type="md" style={[s.bold, pal.text]}>
+                    {following}{' '}
+                  </Text>
+                  <Text type="md" style={[pal.textLight]}>
+                    following
+                  </Text>
+                </Trans>
               </Link>
               <Text type="md" style={[s.bold, pal.text]}>
                 {formatCount(profile.postsCount || 0)}{' '}
@@ -682,7 +698,7 @@ let ProfileHeaderLoaded = ({
         testID="profileHeaderAviButton"
         onPress={onPressAvi}
         accessibilityRole="image"
-        accessibilityLabel={`View ${profile.handle}'s avatar`}
+        accessibilityLabel={_(msg`View ${profile.handle}'s avatar`)}
         accessibilityHint="">
         <View
           style={[pal.view, {borderColor: pal.colors.background}, styles.avi]}>
diff --git a/src/view/com/profile/ProfileHeaderSuggestedFollows.tsx b/src/view/com/profile/ProfileHeaderSuggestedFollows.tsx
index ce5cf92c5..6edc61fcf 100644
--- a/src/view/com/profile/ProfileHeaderSuggestedFollows.tsx
+++ b/src/view/com/profile/ProfileHeaderSuggestedFollows.tsx
@@ -21,6 +21,7 @@ import {useModerationOpts} from '#/state/queries/preferences'
 import {useSuggestedFollowsByActorQuery} from '#/state/queries/suggested-follows'
 import {useProfileShadow} from '#/state/cache/profile-shadow'
 import {useProfileFollowMutationQueue} from '#/state/queries/profile'
+import {Trans} from '@lingui/macro'
 
 const OUTER_PADDING = 10
 const INNER_PADDING = 14
@@ -60,7 +61,7 @@ export function ProfileHeaderSuggestedFollows({
             paddingRight: INNER_PADDING / 2,
           }}>
           <Text type="sm-bold" style={[pal.textLight]}>
-            Suggested for you
+            <Trans>Suggested for you</Trans>
           </Text>
 
           <Pressable
diff --git a/src/view/com/profile/ProfileSubpageHeader.tsx b/src/view/com/profile/ProfileSubpageHeader.tsx
index 0e245f0f4..eaf00f3e6 100644
--- a/src/view/com/profile/ProfileSubpageHeader.tsx
+++ b/src/view/com/profile/ProfileSubpageHeader.tsx
@@ -16,7 +16,7 @@ import {BACK_HITSLOP} from 'lib/constants'
 import {isNative} from 'platform/detection'
 import {useLightboxControls, ImagesLightbox} from '#/state/lightbox'
 import {useLingui} from '@lingui/react'
-import {msg} from '@lingui/macro'
+import {Trans, msg} from '@lingui/macro'
 import {useSetDrawerOpen} from '#/state/shell'
 import {emitSoftReset} from '#/state/events'
 
@@ -153,17 +153,19 @@ export function ProfileSubpageHeader({
             <LoadingPlaceholder width={50} height={8} />
           ) : (
             <Text type="xl" style={[pal.textLight]} numberOfLines={1}>
-              by{' '}
               {!creator ? (
-                '—'
+                <Trans>by —</Trans>
               ) : isOwner ? (
-                'you'
+                <Trans>by you</Trans>
               ) : (
-                <TextLink
-                  text={sanitizeHandle(creator.handle, '@')}
-                  href={makeProfileLink(creator)}
-                  style={pal.textLight}
-                />
+                <Trans>
+                  by{' '}
+                  <TextLink
+                    text={sanitizeHandle(creator.handle, '@')}
+                    href={makeProfileLink(creator)}
+                    style={pal.textLight}
+                  />
+                </Trans>
               )}
             </Text>
           )}
diff --git a/src/view/com/util/AccountDropdownBtn.tsx b/src/view/com/util/AccountDropdownBtn.tsx
index 76d493886..221879df7 100644
--- a/src/view/com/util/AccountDropdownBtn.tsx
+++ b/src/view/com/util/AccountDropdownBtn.tsx
@@ -22,7 +22,7 @@ export function AccountDropdownBtn({account}: {account: SessionAccount}) {
       label: _(msg`Remove account`),
       onPress: () => {
         removeAccount(account)
-        Toast.show('Account removed from quick access')
+        Toast.show(_(msg`Account removed from quick access`))
       },
       icon: {
         ios: {
diff --git a/src/view/com/util/Selector.tsx b/src/view/com/util/Selector.tsx
index 223a069c8..66e363cd4 100644
--- a/src/view/com/util/Selector.tsx
+++ b/src/view/com/util/Selector.tsx
@@ -2,6 +2,8 @@ import React, {createRef, useState, useMemo, useRef} from 'react'
 import {Animated, Pressable, StyleSheet, View} from 'react-native'
 import {Text} from './text/Text'
 import {usePalette} from 'lib/hooks/usePalette'
+import {useLingui} from '@lingui/react'
+import {msg} from '@lingui/macro'
 
 interface Layout {
   x: number
@@ -19,6 +21,7 @@ export function Selector({
   panX: Animated.Value
   onSelect?: (index: number) => void
 }) {
+  const {_} = useLingui()
   const containerRef = useRef<View>(null)
   const pal = usePalette('default')
   const [itemLayouts, setItemLayouts] = useState<undefined | Layout[]>(
@@ -100,8 +103,8 @@ export function Selector({
             testID={`selector-${i}`}
             key={item}
             onPress={() => onPressItem(i)}
-            accessibilityLabel={`Select ${item}`}
-            accessibilityHint={`Select option ${i} of ${numItems}`}>
+            accessibilityLabel={_(msg`Select ${item}`)}
+            accessibilityHint={_(msg`Select option ${i} of ${numItems}`)}>
             <View style={styles.item} ref={itemRefs[i]}>
               <Text
                 style={
diff --git a/src/view/com/util/ViewHeader.tsx b/src/view/com/util/ViewHeader.tsx
index 082cae59c..1ccfcf56c 100644
--- a/src/view/com/util/ViewHeader.tsx
+++ b/src/view/com/util/ViewHeader.tsx
@@ -11,6 +11,8 @@ import {NavigationProp} from 'lib/routes/types'
 import {useMinimalShellMode} from 'lib/hooks/useMinimalShellMode'
 import Animated from 'react-native-reanimated'
 import {useSetDrawerOpen} from '#/state/shell'
+import {msg} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
 
 const BACK_HITSLOP = {left: 20, top: 20, right: 50, bottom: 20}
 
@@ -32,6 +34,7 @@ export function ViewHeader({
   renderButton?: () => JSX.Element
 }) {
   const pal = usePalette('default')
+  const {_} = useLingui()
   const setDrawerOpen = useSetDrawerOpen()
   const navigation = useNavigation<NavigationProp>()
   const {track} = useAnalytics()
@@ -75,9 +78,9 @@ export function ViewHeader({
             hitSlop={BACK_HITSLOP}
             style={canGoBack ? styles.backBtn : styles.backBtnWide}
             accessibilityRole="button"
-            accessibilityLabel={canGoBack ? 'Back' : 'Menu'}
+            accessibilityLabel={canGoBack ? _(msg`Back`) : _(msg`Menu`)}
             accessibilityHint={
-              canGoBack ? '' : 'Access navigation links and settings'
+              canGoBack ? '' : _(msg`Access navigation links and settings`)
             }>
             {canGoBack ? (
               <FontAwesomeIcon
diff --git a/src/view/com/util/error/ErrorMessage.tsx b/src/view/com/util/error/ErrorMessage.tsx
index b4adbb557..a4238b8a4 100644
--- a/src/view/com/util/error/ErrorMessage.tsx
+++ b/src/view/com/util/error/ErrorMessage.tsx
@@ -53,7 +53,9 @@ export function ErrorMessage({
           onPress={onPressTryAgain}
           accessibilityRole="button"
           accessibilityLabel={_(msg`Retry`)}
-          accessibilityHint="Retries the last action, which errored out">
+          accessibilityHint={_(
+            msg`Retries the last action, which errored out`,
+          )}>
           <FontAwesomeIcon
             icon="arrows-rotate"
             style={{color: theme.palette.error.icon}}
diff --git a/src/view/com/util/error/ErrorScreen.tsx b/src/view/com/util/error/ErrorScreen.tsx
index 4cd6dd4b4..45444331c 100644
--- a/src/view/com/util/error/ErrorScreen.tsx
+++ b/src/view/com/util/error/ErrorScreen.tsx
@@ -63,14 +63,16 @@ export function ErrorScreen({
             style={[styles.btn]}
             onPress={onPressTryAgain}
             accessibilityLabel={_(msg`Retry`)}
-            accessibilityHint="Retries the last action, which errored out">
+            accessibilityHint={_(
+              msg`Retries the last action, which errored out`,
+            )}>
             <FontAwesomeIcon
               icon="arrows-rotate"
               style={pal.link as FontAwesomeIconStyle}
               size={16}
             />
             <Text type="button" style={[styles.btnText, pal.link]}>
-              <Trans>Try again</Trans>
+              <Trans context="action">Try again</Trans>
             </Text>
           </Button>
         </View>
diff --git a/src/view/com/util/forms/DropdownButton.tsx b/src/view/com/util/forms/DropdownButton.tsx
index ad8f50f5e..411b77484 100644
--- a/src/view/com/util/forms/DropdownButton.tsx
+++ b/src/view/com/util/forms/DropdownButton.tsx
@@ -75,6 +75,8 @@ export function DropdownButton({
   bottomOffset = 0,
   accessibilityLabel,
 }: PropsWithChildren<DropdownButtonProps>) {
+  const {_} = useLingui()
+
   const ref1 = useRef<TouchableOpacity>(null)
   const ref2 = useRef<View>(null)
 
@@ -141,7 +143,9 @@ export function DropdownButton({
         hitSlop={HITSLOP_10}
         ref={ref1}
         accessibilityRole="button"
-        accessibilityLabel={accessibilityLabel || `Opens ${numItems} options`}
+        accessibilityLabel={
+          accessibilityLabel || _(msg`Opens ${numItems} options`)
+        }
         accessibilityHint="">
         {children}
       </TouchableOpacity>
@@ -247,7 +251,7 @@ const DropdownItems = ({
                 onPress={() => onPressItem(index)}
                 accessibilityRole="button"
                 accessibilityLabel={item.label}
-                accessibilityHint={`Option ${index + 1} of ${numItems}`}>
+                accessibilityHint={_(msg`Option ${index + 1} of ${numItems}`)}>
                 {item.icon && (
                   <FontAwesomeIcon
                     style={styles.icon}
diff --git a/src/view/com/util/forms/PostDropdownBtn.tsx b/src/view/com/util/forms/PostDropdownBtn.tsx
index 1f2e067c2..82373822e 100644
--- a/src/view/com/util/forms/PostDropdownBtn.tsx
+++ b/src/view/com/util/forms/PostDropdownBtn.tsx
@@ -71,32 +71,34 @@ let PostDropdownBtn = ({
   const onDeletePost = React.useCallback(() => {
     postDeleteMutation.mutateAsync({uri: postUri}).then(
       () => {
-        Toast.show('Post deleted')
+        Toast.show(_(msg`Post deleted`))
       },
       e => {
         logger.error('Failed to delete post', {error: e})
-        Toast.show('Failed to delete post, please try again')
+        Toast.show(_(msg`Failed to delete post, please try again`))
       },
     )
-  }, [postUri, postDeleteMutation])
+  }, [postUri, postDeleteMutation, _])
 
   const onToggleThreadMute = React.useCallback(() => {
     try {
       const muted = toggleThreadMute(rootUri)
       if (muted) {
-        Toast.show('You will no longer receive notifications for this thread')
+        Toast.show(
+          _(msg`You will no longer receive notifications for this thread`),
+        )
       } else {
-        Toast.show('You will now receive notifications for this thread')
+        Toast.show(_(msg`You will now receive notifications for this thread`))
       }
     } catch (e) {
       logger.error('Failed to toggle thread mute', {error: e})
     }
-  }, [rootUri, toggleThreadMute])
+  }, [rootUri, toggleThreadMute, _])
 
   const onCopyPostText = React.useCallback(() => {
     Clipboard.setString(record?.text || '')
-    Toast.show('Copied to clipboard')
-  }, [record])
+    Toast.show(_(msg`Copied to clipboard`))
+  }, [record, _])
 
   const onOpenTranslate = React.useCallback(() => {
     Linking.openURL(translatorUrl)
@@ -253,7 +255,7 @@ let PostDropdownBtn = ({
       <NativeDropdown
         testID={testID}
         items={dropdownItems}
-        accessibilityLabel="More post options"
+        accessibilityLabel={_(msg`More post options`)}
         accessibilityHint="">
         <View style={style}>
           <FontAwesomeIcon icon="ellipsis" size={20} color={defaultCtrlColor} />
diff --git a/src/view/com/util/forms/SearchInput.tsx b/src/view/com/util/forms/SearchInput.tsx
index a88046d4c..a78d23c9b 100644
--- a/src/view/com/util/forms/SearchInput.tsx
+++ b/src/view/com/util/forms/SearchInput.tsx
@@ -50,7 +50,7 @@ export function SearchInput({
       <TextInput
         testID="searchTextInput"
         ref={textInput}
-        placeholder="Search"
+        placeholder={_(msg`Search`)}
         placeholderTextColor={pal.colors.textLight}
         selectTextOnFocus
         returnKeyType="search"
diff --git a/src/view/com/util/images/AutoSizedImage.tsx b/src/view/com/util/images/AutoSizedImage.tsx
index 6f203bf06..61cb6f69f 100644
--- a/src/view/com/util/images/AutoSizedImage.tsx
+++ b/src/view/com/util/images/AutoSizedImage.tsx
@@ -4,6 +4,8 @@ import {Image} from 'expo-image'
 import {clamp} from 'lib/numbers'
 import {Dimensions} from 'lib/media/types'
 import * as imageSizes from 'lib/media/image-sizes'
+import {msg} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
 
 const MIN_ASPECT_RATIO = 0.33 // 1/3
 const MAX_ASPECT_RATIO = 10 // 10/1
@@ -29,6 +31,7 @@ export function AutoSizedImage({
   style,
   children = null,
 }: Props) {
+  const {_} = useLingui()
   const [dim, setDim] = React.useState<Dimensions | undefined>(
     dimensionsHint || imageSizes.get(uri),
   )
@@ -64,7 +67,7 @@ export function AutoSizedImage({
           accessible={true} // Must set for `accessibilityLabel` to work
           accessibilityIgnoresInvertColors
           accessibilityLabel={alt}
-          accessibilityHint="Tap to view fully"
+          accessibilityHint={_(msg`Tap to view fully`)}
         />
         {children}
       </Pressable>
diff --git a/src/view/com/util/images/Gallery.tsx b/src/view/com/util/images/Gallery.tsx
index 094b0c56c..e7110372c 100644
--- a/src/view/com/util/images/Gallery.tsx
+++ b/src/view/com/util/images/Gallery.tsx
@@ -2,6 +2,8 @@ import {AppBskyEmbedImages} from '@atproto/api'
 import React, {ComponentProps, FC} from 'react'
 import {StyleSheet, Text, Pressable, View} from 'react-native'
 import {Image} from 'expo-image'
+import {msg} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
 
 type EventFunction = (index: number) => void
 
@@ -22,6 +24,7 @@ export const GalleryItem: FC<GalleryItemProps> = ({
   onPressIn,
   onLongPress,
 }) => {
+  const {_} = useLingui()
   const image = images[index]
   return (
     <View style={styles.fullWidth}>
@@ -31,7 +34,7 @@ export const GalleryItem: FC<GalleryItemProps> = ({
         onLongPress={onLongPress ? () => onLongPress(index) : undefined}
         style={styles.fullWidth}
         accessibilityRole="button"
-        accessibilityLabel={image.alt || 'Image'}
+        accessibilityLabel={image.alt || _(msg`Image`)}
         accessibilityHint="">
         <Image
           source={{uri: image.thumb}}
diff --git a/src/view/com/util/moderation/ContentHider.tsx b/src/view/com/util/moderation/ContentHider.tsx
index 1269b7ebf..249c556ec 100644
--- a/src/view/com/util/moderation/ContentHider.tsx
+++ b/src/view/com/util/moderation/ContentHider.tsx
@@ -63,7 +63,9 @@ export function ContentHider({
           }
         }}
         accessibilityRole="button"
-        accessibilityHint={override ? 'Hide the content' : 'Show the content'}
+        accessibilityHint={
+          override ? _(msg`Hide the content`) : _(msg`Show the content`)
+        }
         accessibilityLabel=""
         style={[
           styles.cover,
diff --git a/src/view/com/util/moderation/PostHider.tsx b/src/view/com/util/moderation/PostHider.tsx
index bffb7ea1a..b1fa71d4a 100644
--- a/src/view/com/util/moderation/PostHider.tsx
+++ b/src/view/com/util/moderation/PostHider.tsx
@@ -9,7 +9,7 @@ import {addStyle} from 'lib/styles'
 import {describeModerationCause} from 'lib/moderation'
 import {ShieldExclamation} from 'lib/icons'
 import {useLingui} from '@lingui/react'
-import {msg} from '@lingui/macro'
+import {Trans, msg} from '@lingui/macro'
 import {useModalControls} from '#/state/modals'
 
 interface Props extends ComponentProps<typeof Link> {
@@ -57,7 +57,9 @@ export function PostHider({
         }
       }}
       accessibilityRole="button"
-      accessibilityHint={override ? 'Hide the content' : 'Show the content'}
+      accessibilityHint={
+        override ? _(msg`Hide the content`) : _(msg`Show the content`)
+      }
       accessibilityLabel=""
       style={[
         styles.description,
@@ -103,7 +105,7 @@ export function PostHider({
       </Text>
       {!moderation.noOverride && (
         <Text type="sm" style={[styles.showBtn, pal.link]}>
-          {override ? 'Hide' : 'Show'}
+          {override ? <Trans>Hide</Trans> : <Trans>Show</Trans>}
         </Text>
       )}
     </Pressable>
diff --git a/src/view/com/util/post-ctrls/PostCtrls.tsx b/src/view/com/util/post-ctrls/PostCtrls.tsx
index a50b52175..575f19bfc 100644
--- a/src/view/com/util/post-ctrls/PostCtrls.tsx
+++ b/src/view/com/util/post-ctrls/PostCtrls.tsx
@@ -26,6 +26,8 @@ import {
 import {useComposerControls} from '#/state/shell/composer'
 import {Shadow} from '#/state/cache/types'
 import {useRequireAuth} from '#/state/session'
+import {msg} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
 
 let PostCtrls = ({
   big,
@@ -43,6 +45,7 @@ let PostCtrls = ({
   onPressReply: () => void
 }): React.ReactNode => {
   const theme = useTheme()
+  const {_} = useLingui()
   const {openComposer} = useComposerControls()
   const {closeModal} = useModalControls()
   const postLikeMutation = usePostLikeMutation()
@@ -176,9 +179,9 @@ let PostCtrls = ({
           requireAuth(() => onPressToggleLike())
         }}
         accessibilityRole="button"
-        accessibilityLabel={`${post.viewer?.like ? 'Unlike' : 'Like'} (${
-          post.likeCount
-        } ${pluralize(post.likeCount || 0, 'like')})`}
+        accessibilityLabel={`${
+          post.viewer?.like ? _(msg`Unlike`) : _(msg`Like`)
+        } (${post.likeCount} ${pluralize(post.likeCount || 0, 'like')})`}
         accessibilityHint=""
         hitSlop={big ? HITSLOP_20 : HITSLOP_10}>
         {post.viewer?.like ? (
diff --git a/src/view/com/util/post-ctrls/RepostButton.tsx b/src/view/com/util/post-ctrls/RepostButton.tsx
index 620852d8e..d45bf1d87 100644
--- a/src/view/com/util/post-ctrls/RepostButton.tsx
+++ b/src/view/com/util/post-ctrls/RepostButton.tsx
@@ -8,6 +8,8 @@ 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 {useLingui} from '@lingui/react'
 
 interface Props {
   isReposted: boolean
@@ -25,6 +27,7 @@ let RepostButton = ({
   onQuote,
 }: Props): React.ReactNode => {
   const theme = useTheme()
+  const {_} = useLingui()
   const {openModal} = useModalControls()
   const requireAuth = useRequireAuth()
 
@@ -53,7 +56,9 @@ let RepostButton = ({
       style={[styles.control, !big && styles.controlPad]}
       accessibilityRole="button"
       accessibilityLabel={`${
-        isReposted ? 'Undo repost' : 'Repost'
+        isReposted
+          ? _(msg`Undo repost`)
+          : _(msg({message: 'Repost', context: 'action'}))
       } (${repostCount} ${pluralize(repostCount || 0, 'repost')})`}
       accessibilityHint=""
       hitSlop={big ? HITSLOP_20 : HITSLOP_10}>
diff --git a/src/view/com/util/post-embeds/QuoteEmbed.tsx b/src/view/com/util/post-embeds/QuoteEmbed.tsx
index fbb89af27..bb8375df6 100644
--- a/src/view/com/util/post-embeds/QuoteEmbed.tsx
+++ b/src/view/com/util/post-embeds/QuoteEmbed.tsx
@@ -17,6 +17,7 @@ import {PostEmbeds} from '.'
 import {PostAlerts} from '../moderation/PostAlerts'
 import {makeProfileLink} from 'lib/routes/links'
 import {InfoCircleIcon} from 'lib/icons'
+import {Trans} from '@lingui/macro'
 
 export function MaybeQuoteEmbed({
   embed,
@@ -52,7 +53,7 @@ export function MaybeQuoteEmbed({
       <View style={[styles.errorContainer, pal.borderDark]}>
         <InfoCircleIcon size={18} style={pal.text} />
         <Text type="lg" style={pal.text}>
-          Blocked
+          <Trans>Blocked</Trans>
         </Text>
       </View>
     )
@@ -61,7 +62,7 @@ export function MaybeQuoteEmbed({
       <View style={[styles.errorContainer, pal.borderDark]}>
         <InfoCircleIcon size={18} style={pal.text} />
         <Text type="lg" style={pal.text}>
-          Deleted
+          <Trans>Deleted</Trans>
         </Text>
       </View>
     )
diff --git a/src/view/screens/AppPasswords.tsx b/src/view/screens/AppPasswords.tsx
index ab4a6a6a8..dc439c367 100644
--- a/src/view/screens/AppPasswords.tsx
+++ b/src/view/screens/AppPasswords.tsx
@@ -62,8 +62,8 @@ export function AppPasswords({}: Props) {
         ]}
         testID="appPasswordsScreen">
         <ErrorScreen
-          title="Oops!"
-          message="There was an issue with fetching your app passwords"
+          title={_(msg`Oops!`)}
+          message={_(msg`There was an issue with fetching your app passwords`)}
           details={cleanError(error)}
         />
       </CenteredView>
diff --git a/src/view/screens/Debug.tsx b/src/view/screens/Debug.tsx
index 0e0464200..f26b1505a 100644
--- a/src/view/screens/Debug.tsx
+++ b/src/view/screens/Debug.tsx
@@ -16,6 +16,8 @@ import {ToggleButton} from '../com/util/forms/ToggleButton'
 import {RadioGroup} from '../com/util/forms/RadioGroup'
 import {ErrorScreen} from '../com/util/error/ErrorScreen'
 import {ErrorMessage} from '../com/util/error/ErrorMessage'
+import {msg} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
 
 const MAIN_VIEWS = ['Base', 'Controls', 'Error', 'Notifs']
 
@@ -48,6 +50,7 @@ function DebugInner({
 }) {
   const [currentView, setCurrentView] = React.useState<number>(0)
   const pal = usePalette('default')
+  const {_} = useLingui()
 
   const renderItem = (item: any) => {
     return (
@@ -57,7 +60,7 @@ function DebugInner({
             type="default-light"
             onPress={onToggleColorScheme}
             isSelected={colorScheme === 'dark'}
-            label="Dark mode"
+            label={_(msg`Dark mode`)}
           />
         </View>
         {item.currentView === 3 ? (
@@ -77,7 +80,7 @@ function DebugInner({
 
   return (
     <View style={[s.hContentRegion, pal.view]}>
-      <ViewHeader title="Debug panel" />
+      <ViewHeader title={_(msg`Debug panel`)} />
       <ViewSelector
         swipeEnabled
         sections={MAIN_VIEWS}
diff --git a/src/view/screens/Feeds.tsx b/src/view/screens/Feeds.tsx
index dbdb6d9ca..e0126bd48 100644
--- a/src/view/screens/Feeds.tsx
+++ b/src/view/screens/Feeds.tsx
@@ -328,7 +328,7 @@ export function FeedsScreen(_props: Props) {
         hitSlop={10}
         accessibilityRole="button"
         accessibilityLabel={_(msg`Edit Saved Feeds`)}
-        accessibilityHint="Opens screen to edit Saved Feeds">
+        accessibilityHint={_(msg`Opens screen to edit Saved Feeds`)}>
         <CogIcon size={22} strokeWidth={2} style={pal.textLight} />
       </Link>
     )
diff --git a/src/view/screens/Lists.tsx b/src/view/screens/Lists.tsx
index d28db7c6c..23d6c8fac 100644
--- a/src/view/screens/Lists.tsx
+++ b/src/view/screens/Lists.tsx
@@ -73,7 +73,7 @@ export function ListsScreen({}: Props) {
             }}>
             <FontAwesomeIcon icon="plus" color={pal.colors.text} />
             <Text type="button" style={pal.text}>
-              <Trans>New</Trans>
+              <Trans context="action">New</Trans>
             </Text>
           </Button>
         </View>
diff --git a/src/view/screens/Log.tsx b/src/view/screens/Log.tsx
index 8680b851b..e727a1fb8 100644
--- a/src/view/screens/Log.tsx
+++ b/src/view/screens/Log.tsx
@@ -50,7 +50,9 @@ export function LogScreen({}: NativeStackScreenProps<
                   style={[styles.entry, pal.border, pal.view]}
                   onPress={toggler(entry.id)}
                   accessibilityLabel={_(msg`View debug entry`)}
-                  accessibilityHint="Opens additional details for a debug entry">
+                  accessibilityHint={_(
+                    msg`Opens additional details for a debug entry`,
+                  )}>
                   {entry.level === 'debug' ? (
                     <FontAwesomeIcon icon="info" />
                   ) : (
diff --git a/src/view/screens/PostThread.tsx b/src/view/screens/PostThread.tsx
index 6f8434412..aaadbf399 100644
--- a/src/view/screens/PostThread.tsx
+++ b/src/view/screens/PostThread.tsx
@@ -78,7 +78,9 @@ export function PostThreadScreen({route}: Props) {
 
   return (
     <View style={s.hContentRegion}>
-      {isMobile && <ViewHeader title={_(msg`Post`)} />}
+      {isMobile && (
+        <ViewHeader title={_(msg({message: 'Post', context: 'description'}))} />
+      )}
       <View style={s.flex1}>
         {uriError ? (
           <CenteredView>
diff --git a/src/view/screens/PreferencesExternalEmbeds.tsx b/src/view/screens/PreferencesExternalEmbeds.tsx
index 24e7d56df..1e8cedf7e 100644
--- a/src/view/screens/PreferencesExternalEmbeds.tsx
+++ b/src/view/screens/PreferencesExternalEmbeds.tsx
@@ -72,7 +72,7 @@ export function PreferencesExternalEmbeds({}: Props) {
           </View>
         </View>
         <Text type="xl-bold" style={[pal.text, styles.heading]}>
-          Enable media players for
+          <Trans>Enable media players for</Trans>
         </Text>
         {Object.entries(externalEmbedLabels).map(([key, label]) => (
           <PrefSelector
diff --git a/src/view/screens/PreferencesHomeFeed.tsx b/src/view/screens/PreferencesHomeFeed.tsx
index 874272831..7ad870937 100644
--- a/src/view/screens/PreferencesHomeFeed.tsx
+++ b/src/view/screens/PreferencesHomeFeed.tsx
@@ -27,6 +27,7 @@ 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,10 +65,12 @@ function RepliesThresholdInput({
       />
       <Text type="xs" style={pal.text}>
         {value === 0
-          ? `Show all replies`
-          : `Show replies with at least ${value} ${
-              value > 1 ? `likes` : `like`
-            }`}
+          ? _(msg`Show all replies`)
+          : _(
+              msg`Show replies with at least ${value} ${
+                value > 1 ? `likes` : `like`
+              }`,
+            )}
       </Text>
     </View>
   )
diff --git a/src/view/screens/PreferencesThreads.tsx b/src/view/screens/PreferencesThreads.tsx
index 35a010b55..321c67293 100644
--- a/src/view/screens/PreferencesThreads.tsx
+++ b/src/view/screens/PreferencesThreads.tsx
@@ -159,7 +159,7 @@ export function PreferencesThreads({navigation}: Props) {
           accessibilityLabel={_(msg`Confirm`)}
           accessibilityHint="">
           <Text style={[s.white, s.bold, s.f18]}>
-            <Trans>Done</Trans>
+            <Trans context="action">Done</Trans>
           </Text>
         </TouchableOpacity>
       </View>
diff --git a/src/view/screens/Profile.tsx b/src/view/screens/Profile.tsx
index 4558ae33d..7fc4d7a20 100644
--- a/src/view/screens/Profile.tsx
+++ b/src/view/screens/Profile.tsx
@@ -371,6 +371,7 @@ const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
     {feed, headerHeight, isFocused, scrollElRef, ignoreFilterFor},
     ref,
   ) {
+    const {_} = useLingui()
     const queryClient = useQueryClient()
     const [hasNew, setHasNew] = React.useState(false)
     const [isScrolledDown, setIsScrolledDown] = React.useState(false)
@@ -388,8 +389,8 @@ const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
     }))
 
     const renderPostsEmpty = React.useCallback(() => {
-      return <EmptyState icon="feed" message="This feed is empty!" />
-    }, [])
+      return <EmptyState icon="feed" message={_(msg`This feed is empty!`)} />
+    }, [_])
 
     return (
       <View>
@@ -408,7 +409,7 @@ const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
         {(isScrolledDown || hasNew) && (
           <LoadLatestBtn
             onPress={onScrollToTop}
-            label="Load new posts"
+            label={_(msg`Load new posts`)}
             showIndicator={hasNew}
           />
         )}
diff --git a/src/view/screens/ProfileFeed.tsx b/src/view/screens/ProfileFeed.tsx
index 211306c0d..4f5f300af 100644
--- a/src/view/screens/ProfileFeed.tsx
+++ b/src/view/screens/ProfileFeed.tsx
@@ -214,11 +214,21 @@ export function ProfileFeedScreenInner({
       }
     } catch (err) {
       Toast.show(
-        'There was an an issue updating your feeds, please check your internet connection and try again.',
+        _(
+          msg`There was an an issue updating your feeds, please check your internet connection and try again.`,
+        ),
       )
       logger.error('Failed up update feeds', {error: err})
     }
-  }, [feedInfo, isSaved, saveFeed, removeFeed, resetSaveFeed, resetRemoveFeed])
+  }, [
+    feedInfo,
+    isSaved,
+    saveFeed,
+    removeFeed,
+    resetSaveFeed,
+    resetRemoveFeed,
+    _,
+  ])
 
   const onTogglePinned = React.useCallback(async () => {
     try {
@@ -232,10 +242,10 @@ export function ProfileFeedScreenInner({
         resetPinFeed()
       }
     } catch (e) {
-      Toast.show('There was an issue contacting the server')
+      Toast.show(_(msg`There was an issue contacting the server`))
       logger.error('Failed to toggle pinned feed', {error: e})
     }
-  }, [isPinned, feedInfo, pinFeed, unpinFeed, resetPinFeed, resetUnpinFeed])
+  }, [isPinned, feedInfo, pinFeed, unpinFeed, resetPinFeed, resetUnpinFeed, _])
 
   const onPressShare = React.useCallback(() => {
     const url = toShareUrl(feedInfo.route.href)
@@ -341,7 +351,7 @@ export function ProfileFeedScreenInner({
             <Button
               disabled={isSavePending || isRemovePending}
               type="default"
-              label={isSaved ? 'Unsave' : 'Save'}
+              label={isSaved ? _(msg`Unsave`) : _(msg`Save`)}
               onPress={onToggleSaved}
               style={styles.btn}
             />
@@ -349,7 +359,7 @@ export function ProfileFeedScreenInner({
               testID={isPinned ? 'unpinBtn' : 'pinBtn'}
               disabled={isPinPending || isUnpinPending}
               type={isPinned ? 'default' : 'inverted'}
-              label={isPinned ? 'Unpin' : 'Pin to home'}
+              label={isPinned ? _(msg`Unpin`) : _(msg`Pin to home`)}
               onPress={onTogglePinned}
               style={styles.btn}
             />
@@ -444,6 +454,7 @@ interface FeedSectionProps {
 }
 const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
   function FeedSectionImpl({feed, headerHeight, scrollElRef, isFocused}, ref) {
+    const {_} = useLingui()
     const [hasNew, setHasNew] = React.useState(false)
     const [isScrolledDown, setIsScrolledDown] = React.useState(false)
     const queryClient = useQueryClient()
@@ -470,8 +481,8 @@ const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
     }, [onScrollToTop, isScreenFocused])
 
     const renderPostsEmpty = useCallback(() => {
-      return <EmptyState icon="feed" message="This feed is empty!" />
-    }, [])
+      return <EmptyState icon="feed" message={_(msg`This feed is empty!`)} />
+    }, [_])
 
     return (
       <View>
@@ -488,7 +499,7 @@ const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
         {(isScrolledDown || hasNew) && (
           <LoadLatestBtn
             onPress={onScrollToTop}
-            label="Load new posts"
+            label={_(msg`Load new posts`)}
             showIndicator={hasNew}
           />
         )}
@@ -542,11 +553,13 @@ function AboutSection({
       }
     } catch (err) {
       Toast.show(
-        'There was an an issue contacting the server, please check your internet connection and try again.',
+        _(
+          msg`There was an an issue contacting the server, please check your internet connection and try again.`,
+        ),
       )
       logger.error('Failed up toggle like', {error: err})
     }
-  }, [likeUri, isLiked, feedInfo, likeFeed, unlikeFeed, track])
+  }, [likeUri, isLiked, feedInfo, likeFeed, unlikeFeed, track, _])
 
   return (
     <ScrollView
@@ -597,24 +610,28 @@ function AboutSection({
           {typeof likeCount === 'number' && (
             <TextLink
               href={makeCustomFeedLink(feedOwnerDid, feedRkey, 'liked-by')}
-              text={`Liked by ${likeCount} ${pluralize(likeCount, 'user')}`}
+              text={_(
+                msg`Liked by ${likeCount} ${pluralize(likeCount, 'user')}`,
+              )}
               style={[pal.textLight, s.semiBold]}
             />
           )}
         </View>
         <Text type="md" style={[pal.textLight]} numberOfLines={1}>
-          Created by{' '}
           {isOwner ? (
-            'you'
+            <Trans>Created by you</Trans>
           ) : (
-            <TextLink
-              text={sanitizeHandle(feedInfo.creatorHandle, '@')}
-              href={makeProfileLink({
-                did: feedInfo.creatorDid,
-                handle: feedInfo.creatorHandle,
-              })}
-              style={pal.textLight}
-            />
+            <Trans>
+              Created by{' '}
+              <TextLink
+                text={sanitizeHandle(feedInfo.creatorHandle, '@')}
+                href={makeProfileLink({
+                  did: feedInfo.creatorDid,
+                  handle: feedInfo.creatorHandle,
+                })}
+                style={pal.textLight}
+              />
+            </Trans>
           )}
         </Text>
       </View>
diff --git a/src/view/screens/ProfileList.tsx b/src/view/screens/ProfileList.tsx
index c51758ae5..30999b518 100644
--- a/src/view/screens/ProfileList.tsx
+++ b/src/view/screens/ProfileList.tsx
@@ -68,6 +68,7 @@ interface SectionRef {
 
 type Props = NativeStackScreenProps<CommonNavigatorParams, 'ProfileList'>
 export function ProfileListScreen(props: Props) {
+  const {_} = useLingui()
   const {name: handleOrDid, rkey} = props.route.params
   const {data: resolvedUri, error: resolveError} = useResolveUriQuery(
     AtUri.make(handleOrDid, 'app.bsky.graph.list', rkey).toString(),
@@ -78,7 +79,9 @@ export function ProfileListScreen(props: Props) {
     return (
       <CenteredView>
         <ErrorScreen
-          error={`We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @${handleOrDid}.`}
+          error={_(
+            msg`We're sorry, but we were unable to resolve this list. If this persists, please contact the list creator, @${handleOrDid}.`,
+          )}
         />
       </CenteredView>
     )
@@ -260,10 +263,10 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
         await pinFeed({uri: list.uri})
       }
     } catch (e) {
-      Toast.show('There was an issue contacting the server')
+      Toast.show(_(msg`There was an issue contacting the server`))
       logger.error('Failed to toggle pinned feed', {error: e})
     }
-  }, [list.uri, isPinned, pinFeed, unpinFeed])
+  }, [list.uri, isPinned, pinFeed, unpinFeed, _])
 
   const onSubscribeMute = useCallback(() => {
     openModal({
@@ -272,15 +275,17 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
       message: _(
         msg`Muting is private. Muted accounts can interact with you, but you will not see their posts or receive notifications from them.`,
       ),
-      confirmBtnText: 'Mute this List',
+      confirmBtnText: _(msg`Mute this List`),
       async onPressConfirm() {
         try {
           await listMuteMutation.mutateAsync({uri: list.uri, mute: true})
-          Toast.show('List muted')
+          Toast.show(_(msg`List muted`))
           track('Lists:Mute')
         } catch {
           Toast.show(
-            'There was an issue. Please check your internet connection and try again.',
+            _(
+              msg`There was an issue. Please check your internet connection and try again.`,
+            ),
           )
         }
       },
@@ -293,14 +298,16 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
   const onUnsubscribeMute = useCallback(async () => {
     try {
       await listMuteMutation.mutateAsync({uri: list.uri, mute: false})
-      Toast.show('List unmuted')
+      Toast.show(_(msg`List unmuted`))
       track('Lists:Unmute')
     } catch {
       Toast.show(
-        'There was an issue. Please check your internet connection and try again.',
+        _(
+          msg`There was an issue. Please check your internet connection and try again.`,
+        ),
       )
     }
-  }, [list, listMuteMutation, track])
+  }, [list, listMuteMutation, track, _])
 
   const onSubscribeBlock = useCallback(() => {
     openModal({
@@ -309,15 +316,17 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
       message: _(
         msg`Blocking is public. Blocked accounts cannot reply in your threads, mention you, or otherwise interact with you.`,
       ),
-      confirmBtnText: 'Block this List',
+      confirmBtnText: _(msg`Block this List`),
       async onPressConfirm() {
         try {
           await listBlockMutation.mutateAsync({uri: list.uri, block: true})
-          Toast.show('List blocked')
+          Toast.show(_(msg`List blocked`))
           track('Lists:Block')
         } catch {
           Toast.show(
-            'There was an issue. Please check your internet connection and try again.',
+            _(
+              msg`There was an issue. Please check your internet connection and try again.`,
+            ),
           )
         }
       },
@@ -330,14 +339,16 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
   const onUnsubscribeBlock = useCallback(async () => {
     try {
       await listBlockMutation.mutateAsync({uri: list.uri, block: false})
-      Toast.show('List unblocked')
+      Toast.show(_(msg`List unblocked`))
       track('Lists:Unblock')
     } catch {
       Toast.show(
-        'There was an issue. Please check your internet connection and try again.',
+        _(
+          msg`There was an issue. Please check your internet connection and try again.`,
+        ),
       )
     }
-  }, [list, listBlockMutation, track])
+  }, [list, listBlockMutation, track, _])
 
   const onPressEdit = useCallback(() => {
     openModal({
@@ -353,7 +364,7 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
       message: _(msg`Are you sure?`),
       async onPressConfirm() {
         await listDeleteMutation.mutateAsync({uri: list.uri})
-        Toast.show('List deleted')
+        Toast.show(_(msg`List deleted`))
         track('Lists:Delete')
         if (navigation.canGoBack()) {
           navigation.goBack()
@@ -545,7 +556,7 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
         <Button
           testID={isPinned ? 'unpinBtn' : 'pinBtn'}
           type={isPinned ? 'default' : 'inverted'}
-          label={isPinned ? 'Unpin' : 'Pin to home'}
+          label={isPinned ? _(msg`Unpin`) : _(msg`Pin to home`)}
           onPress={onTogglePinned}
           disabled={isPending}
         />
@@ -554,14 +565,14 @@ function Header({rkey, list}: {rkey: string; list: AppBskyGraphDefs.ListView}) {
           <Button
             testID="unblockBtn"
             type="default"
-            label="Unblock"
+            label={_(msg`Unblock`)}
             onPress={onUnsubscribeBlock}
           />
         ) : isMuting ? (
           <Button
             testID="unmuteBtn"
             type="default"
-            label="Unmute"
+            label={_(msg`Unmute`)}
             onPress={onUnsubscribeMute}
           />
         ) : (
@@ -603,6 +614,7 @@ const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
     const [hasNew, setHasNew] = React.useState(false)
     const [isScrolledDown, setIsScrolledDown] = React.useState(false)
     const isScreenFocused = useIsFocused()
+    const {_} = useLingui()
 
     const onScrollToTop = useCallback(() => {
       scrollElRef.current?.scrollToOffset({
@@ -624,8 +636,8 @@ const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
     }, [onScrollToTop, isScreenFocused])
 
     const renderPostsEmpty = useCallback(() => {
-      return <EmptyState icon="feed" message="This feed is empty!" />
-    }, [])
+      return <EmptyState icon="feed" message={_(msg`This feed is empty!`)} />
+    }, [_])
 
     return (
       <View>
@@ -643,7 +655,7 @@ const FeedSection = React.forwardRef<SectionRef, FeedSectionProps>(
         {(isScrolledDown || hasNew) && (
           <LoadLatestBtn
             onPress={onScrollToTop}
-            label="Load new posts"
+            label={_(msg`Load new posts`)}
             showIndicator={hasNew}
           />
         )}
@@ -721,15 +733,30 @@ const AboutSection = React.forwardRef<SectionRef, AboutSectionProps>(
               </Text>
             )}
             <Text type="md" style={[pal.textLight]} numberOfLines={1}>
-              {isCurateList ? 'User list' : 'Moderation list'} by{' '}
-              {isOwner ? (
-                'you'
+              {isCurateList ? (
+                isOwner ? (
+                  <Trans>User list by you</Trans>
+                ) : (
+                  <Trans>
+                    User list by{' '}
+                    <TextLink
+                      text={sanitizeHandle(list.creator.handle || '', '@')}
+                      href={makeProfileLink(list.creator)}
+                      style={pal.textLight}
+                    />
+                  </Trans>
+                )
+              ) : isOwner ? (
+                <Trans>Moderation list by you</Trans>
               ) : (
-                <TextLink
-                  text={sanitizeHandle(list.creator.handle || '', '@')}
-                  href={makeProfileLink(list.creator)}
-                  style={pal.textLight}
-                />
+                <Trans>
+                  Moderation list by{' '}
+                  <TextLink
+                    text={sanitizeHandle(list.creator.handle || '', '@')}
+                    href={makeProfileLink(list.creator)}
+                    style={pal.textLight}
+                  />
+                </Trans>
               )}
             </Text>
           </View>
@@ -782,11 +809,11 @@ const AboutSection = React.forwardRef<SectionRef, AboutSectionProps>(
       return (
         <EmptyState
           icon="users-slash"
-          message="This list is empty!"
+          message={_(msg`This list is empty!`)}
           style={{paddingTop: 40}}
         />
       )
-    }, [])
+    }, [_])
 
     return (
       <View>
@@ -802,7 +829,7 @@ const AboutSection = React.forwardRef<SectionRef, AboutSectionProps>(
         {isScrolledDown && (
           <LoadLatestBtn
             onPress={onScrollToTop}
-            label="Scroll to top"
+            label={_(msg`Scroll to top`)}
             showIndicator={false}
           />
         )}
@@ -846,7 +873,7 @@ function ErrorScreen({error}: {error: string}) {
         <Button
           type="default"
           accessibilityLabel={_(msg`Go Back`)}
-          accessibilityHint="Return to previous page"
+          accessibilityHint={_(msg`Return to previous page`)}
           onPress={onPressBack}
           style={{flexShrink: 1}}>
           <Text type="button" style={pal.text}>
diff --git a/src/view/screens/SavedFeeds.tsx b/src/view/screens/SavedFeeds.tsx
index 8a16ffdf2..19ae37f0c 100644
--- a/src/view/screens/SavedFeeds.tsx
+++ b/src/view/screens/SavedFeeds.tsx
@@ -160,7 +160,7 @@ export function SavedFeeds({}: Props) {
                 type="sm"
                 style={pal.link}
                 href="https://github.com/bluesky-social/feed-generator"
-                text="See this guide"
+                text={_(msg`See this guide`)}
               />{' '}
               for more information.
             </Trans>
@@ -188,6 +188,7 @@ function ListItem({
   >['reset']
 }) {
   const pal = usePalette('default')
+  const {_} = useLingui()
   const {isPending: isPinPending, mutateAsync: pinFeed} = usePinFeedMutation()
   const {isPending: isUnpinPending, mutateAsync: unpinFeed} =
     useUnpinFeedMutation()
@@ -205,10 +206,10 @@ function ListItem({
         await pinFeed({uri: feedUri})
       }
     } catch (e) {
-      Toast.show('There was an issue contacting the server')
+      Toast.show(_(msg`There was an issue contacting the server`))
       logger.error('Failed to toggle pinned feed', {error: e})
     }
-  }, [feedUri, isPinned, pinFeed, unpinFeed, resetSaveFeedsMutationState])
+  }, [feedUri, isPinned, pinFeed, unpinFeed, resetSaveFeedsMutationState, _])
 
   const onPressUp = React.useCallback(async () => {
     if (!isPinned) return
@@ -227,10 +228,10 @@ function ListItem({
         index: pinned.indexOf(feedUri),
       })
     } catch (e) {
-      Toast.show('There was an issue contacting the server')
+      Toast.show(_(msg`There was an issue contacting the server`))
       logger.error('Failed to set pinned feed order', {error: e})
     }
-  }, [feedUri, isPinned, setSavedFeeds, currentFeeds])
+  }, [feedUri, isPinned, setSavedFeeds, currentFeeds, _])
 
   const onPressDown = React.useCallback(async () => {
     if (!isPinned) return
@@ -248,10 +249,10 @@ function ListItem({
         index: pinned.indexOf(feedUri),
       })
     } catch (e) {
-      Toast.show('There was an issue contacting the server')
+      Toast.show(_(msg`There was an issue contacting the server`))
       logger.error('Failed to set pinned feed order', {error: e})
     }
-  }, [feedUri, isPinned, setSavedFeeds, currentFeeds])
+  }, [feedUri, isPinned, setSavedFeeds, currentFeeds, _])
 
   return (
     <Pressable
diff --git a/src/view/screens/Search/Search.tsx b/src/view/screens/Search/Search.tsx
index da3a82a4d..33356662a 100644
--- a/src/view/screens/Search/Search.tsx
+++ b/src/view/screens/Search/Search.tsx
@@ -535,7 +535,7 @@ export function SearchScreen(
             style={styles.headerMenuBtn}
             accessibilityRole="button"
             accessibilityLabel={_(msg`Menu`)}
-            accessibilityHint="Access navigation links and settings">
+            accessibilityHint={_(msg`Access navigation links and settings`)}>
             <FontAwesomeIcon
               icon="bars"
               size={18}
@@ -556,7 +556,7 @@ export function SearchScreen(
           <TextInput
             testID="searchTextInput"
             ref={textInput}
-            placeholder="Search"
+            placeholder={_(msg`Search`)}
             placeholderTextColor={pal.colors.textLight}
             selectTextOnFocus
             returnKeyType="search"
diff --git a/src/view/screens/Settings.tsx b/src/view/screens/Settings.tsx
index 8278b753e..c078e7a23 100644
--- a/src/view/screens/Settings.tsx
+++ b/src/view/screens/Settings.tsx
@@ -117,7 +117,7 @@ function SettingsAccountCard({account}: {account: SessionAccount}) {
         did: currentAccount?.did,
         handle: currentAccount?.handle,
       })}
-      title="Your profile"
+      title={_(msg`Your profile`)}
       noFeedback>
       {contents}
     </Link>
@@ -129,8 +129,8 @@ function SettingsAccountCard({account}: {account: SessionAccount}) {
         isSwitchingAccounts ? undefined : () => onPressSwitchAccount(account)
       }
       accessibilityRole="button"
-      accessibilityLabel={`Switch to ${account.handle}`}
-      accessibilityHint="Switches the account you are logged in to">
+      accessibilityLabel={_(msg`Switch to ${account.handle}`)}
+      accessibilityHint={_(msg`Switches the account you are logged in to`)}>
       {contents}
     </TouchableOpacity>
   )
@@ -318,7 +318,7 @@ export function SettingsScreen({}: Props) {
               </Text>
               <Link onPress={() => openModal({name: 'change-email'})}>
                 <Text type="lg" style={pal.link}>
-                  <Trans>Change</Trans>
+                  <Trans context="action">Change</Trans>
                 </Text>
               </Link>
             </View>
@@ -368,7 +368,7 @@ export function SettingsScreen({}: Props) {
           onPress={isSwitchingAccounts ? undefined : onPressAddAccount}
           accessibilityRole="button"
           accessibilityLabel={_(msg`Add account`)}
-          accessibilityHint="Create a new Bluesky account">
+          accessibilityHint={_(msg`Create a new Bluesky account`)}>
           <View style={[styles.iconContainer, pal.btn]}>
             <FontAwesomeIcon
               icon="plus"
@@ -396,7 +396,7 @@ export function SettingsScreen({}: Props) {
           onPress={isSwitchingAccounts ? undefined : onPressInviteCodes}
           accessibilityRole="button"
           accessibilityLabel={_(msg`Invite`)}
-          accessibilityHint="Opens invite code list"
+          accessibilityHint={_(msg`Opens invite code list`)}
           disabled={invites?.disabled}>
           <View
             style={[
@@ -453,20 +453,20 @@ export function SettingsScreen({}: Props) {
               label={_(msg`System`)}
               left
               onSelect={() => setColorMode('system')}
-              accessibilityHint="Set color theme to system setting"
+              accessibilityHint={_(msg`Set color theme to system setting`)}
             />
             <SelectableBtn
               selected={colorMode === 'light'}
               label={_(msg`Light`)}
               onSelect={() => setColorMode('light')}
-              accessibilityHint="Set color theme to light"
+              accessibilityHint={_(msg`Set color theme to light`)}
             />
             <SelectableBtn
               selected={colorMode === 'dark'}
               label={_(msg`Dark`)}
               right
               onSelect={() => setColorMode('dark')}
-              accessibilityHint="Set color theme to dark"
+              accessibilityHint={_(msg`Set color theme to dark`)}
             />
           </View>
         </View>
@@ -544,8 +544,8 @@ export function SettingsScreen({}: Props) {
           ]}
           onPress={isSwitchingAccounts ? undefined : onPressLanguageSettings}
           accessibilityRole="button"
-          accessibilityHint="Language settings"
-          accessibilityLabel={_(msg`Opens configurable language settings`)}>
+          accessibilityLabel={_(msg`Language settings`)}
+          accessibilityHint={_(msg`Opens configurable language settings`)}>
           <View style={[styles.iconContainer, pal.btn]}>
             <FontAwesomeIcon
               icon="language"
@@ -569,8 +569,8 @@ export function SettingsScreen({}: Props) {
               : () => navigation.navigate('Moderation')
           }
           accessibilityRole="button"
-          accessibilityHint=""
-          accessibilityLabel={_(msg`Opens moderation settings`)}>
+          accessibilityLabel={_(msg`Moderation settings`)}
+          accessibilityHint={_(msg`Opens moderation settings`)}>
           <View style={[styles.iconContainer, pal.btn]}>
             <HandIcon style={pal.text} size={18} strokeWidth={6} />
           </View>
@@ -598,8 +598,8 @@ export function SettingsScreen({}: Props) {
               : () => navigation.navigate('PreferencesExternalEmbeds')
           }
           accessibilityRole="button"
-          accessibilityHint=""
-          accessibilityLabel={_(msg`Opens external embeds settings`)}>
+          accessibilityLabel={_(msg`External media settings`)}
+          accessibilityHint={_(msg`Opens external embeds settings`)}>
           <View style={[styles.iconContainer, pal.btn]}>
             <FontAwesomeIcon
               icon={['far', 'circle-play']}
@@ -625,8 +625,8 @@ export function SettingsScreen({}: Props) {
           ]}
           onPress={onPressAppPasswords}
           accessibilityRole="button"
-          accessibilityHint="Open app password settings"
-          accessibilityLabel={_(msg`Opens the app password settings page`)}>
+          accessibilityLabel={_(msg`App password settings`)}
+          accessibilityHint={_(msg`Opens the app password settings page`)}>
           <View style={[styles.iconContainer, pal.btn]}>
             <FontAwesomeIcon
               icon="lock"
@@ -647,7 +647,7 @@ export function SettingsScreen({}: Props) {
           onPress={isSwitchingAccounts ? undefined : onPressChangeHandle}
           accessibilityRole="button"
           accessibilityLabel={_(msg`Change handle`)}
-          accessibilityHint="Choose a new Bluesky username or create">
+          accessibilityHint={_(msg`Choose a new Bluesky username or create`)}>
           <View style={[styles.iconContainer, pal.btn]}>
             <FontAwesomeIcon
               icon="at"
@@ -668,7 +668,9 @@ export function SettingsScreen({}: Props) {
           accessible={true}
           accessibilityRole="button"
           accessibilityLabel={_(msg`Delete account`)}
-          accessibilityHint="Opens modal for account deletion confirmation. Requires email code.">
+          accessibilityHint={_(
+            msg`Opens modal for account deletion confirmation. Requires email code.`,
+          )}>
           <View style={[styles.iconContainer, dangerBg]}>
             <FontAwesomeIcon
               icon={['far', 'trash-can']}
@@ -708,8 +710,8 @@ export function SettingsScreen({}: Props) {
               style={[pal.view, styles.linkCardNoIcon]}
               onPress={onPressStorybook}
               accessibilityRole="button"
-              accessibilityHint="Open storybook page"
-              accessibilityLabel={_(msg`Opens the storybook page`)}>
+              accessibilityLabel={_(msg`Open storybook page`)}
+              accessibilityHint={_(msg`Opens the storybook page`)}>
               <Text type="lg" style={pal.text}>
                 <Trans>Storybook</Trans>
               </Text>
@@ -718,8 +720,8 @@ export function SettingsScreen({}: Props) {
               style={[pal.view, styles.linkCardNoIcon]}
               onPress={onPressResetPreferences}
               accessibilityRole="button"
-              accessibilityHint="Reset preferences"
-              accessibilityLabel={_(msg`Resets the preferences state`)}>
+              accessibilityLabel={_(msg`Reset preferences`)}
+              accessibilityHint={_(msg`Resets the preferences state`)}>
               <Text type="lg" style={pal.text}>
                 <Trans>Reset preferences state</Trans>
               </Text>
@@ -728,8 +730,8 @@ export function SettingsScreen({}: Props) {
               style={[pal.view, styles.linkCardNoIcon]}
               onPress={onPressResetOnboarding}
               accessibilityRole="button"
-              accessibilityHint="Reset onboarding"
-              accessibilityLabel={_(msg`Resets the onboarding state`)}>
+              accessibilityLabel={_(msg`Reset onboarding`)}
+              accessibilityHint={_(msg`Resets the onboarding state`)}>
               <Text type="lg" style={pal.text}>
                 <Trans>Reset onboarding state</Trans>
               </Text>
@@ -738,8 +740,8 @@ export function SettingsScreen({}: Props) {
               style={[pal.view, styles.linkCardNoIcon]}
               onPress={clearAllLegacyStorage}
               accessibilityRole="button"
-              accessibilityHint="Clear all legacy storage data"
-              accessibilityLabel={_(msg`Clear all legacy storage data`)}>
+              accessibilityLabel={_(msg`Clear all legacy storage data`)}
+              accessibilityHint={_(msg`Clear all legacy storage data`)}>
               <Text type="lg" style={pal.text}>
                 <Trans>
                   Clear all legacy storage data (restart after this)
@@ -750,8 +752,8 @@ export function SettingsScreen({}: Props) {
               style={[pal.view, styles.linkCardNoIcon]}
               onPress={clearAllStorage}
               accessibilityRole="button"
-              accessibilityHint="Clear all storage data"
-              accessibilityLabel={_(msg`Clear all storage data`)}>
+              accessibilityLabel={_(msg`Clear all storage data`)}
+              accessibilityHint={_(msg`Clear all storage data`)}>
               <Text type="lg" style={pal.text}>
                 <Trans>Clear all storage data (restart after this)</Trans>
               </Text>
diff --git a/src/view/screens/Support.tsx b/src/view/screens/Support.tsx
index 6856f6759..9e7d36ec7 100644
--- a/src/view/screens/Support.tsx
+++ b/src/view/screens/Support.tsx
@@ -34,10 +34,10 @@ export const SupportScreen = (_props: Props) => {
         </Text>
         <Text style={[pal.text, s.p20]}>
           <Trans>
-            The support form has been moved. If you need help, please
+            The support form has been moved. If you need help, please{' '}
             <TextLink
               href={HELP_DESK_URL}
-              text=" click here"
+              text={_(msg`click here`)}
               style={pal.link}
             />{' '}
             or visit {HELP_DESK_URL} to get in touch with us.
diff --git a/src/view/shell/Drawer.tsx b/src/view/shell/Drawer.tsx
index 14bc6af26..6f748755a 100644
--- a/src/view/shell/Drawer.tsx
+++ b/src/view/shell/Drawer.tsx
@@ -68,7 +68,7 @@ let DrawerProfileCard = ({
     <TouchableOpacity
       testID="profileCardButton"
       accessibilityLabel={_(msg`Profile`)}
-      accessibilityHint="Navigates to your profile"
+      accessibilityHint={_(msg`Navigates to your profile`)}
       onPress={onPressProfile}>
       <UserAvatar
         size={80}
@@ -435,7 +435,9 @@ let NotificationsMenuItem = ({
       label={_(msg`Notifications`)}
       accessibilityLabel={_(msg`Notifications`)}
       accessibilityHint={
-        numUnreadNotifications === '' ? '' : `${numUnreadNotifications} unread`
+        numUnreadNotifications === ''
+          ? ''
+          : _(msg`${numUnreadNotifications} unread`)
       }
       count={numUnreadNotifications}
       bold={isActive}
diff --git a/src/view/shell/desktop/LeftNav.tsx b/src/view/shell/desktop/LeftNav.tsx
index 3925b5180..c84e86b95 100644
--- a/src/view/shell/desktop/LeftNav.tsx
+++ b/src/view/shell/desktop/LeftNav.tsx
@@ -255,7 +255,7 @@ function ComposeBtn() {
           />
         </View>
         <Text type="button" style={styles.newPostBtnLabel}>
-          <Trans>New Post</Trans>
+          <Trans context="action">New Post</Trans>
         </Text>
       </TouchableOpacity>
     </View>
diff --git a/src/view/shell/desktop/RightNav.tsx b/src/view/shell/desktop/RightNav.tsx
index 894624a6e..842991d6f 100644
--- a/src/view/shell/desktop/RightNav.tsx
+++ b/src/view/shell/desktop/RightNav.tsx
@@ -56,7 +56,7 @@ export function DesktopRightNav({routeName}: {routeName: string}) {
           {isSandbox ? (
             <View style={[palError.view, styles.messageLine, s.p10]}>
               <Text type="md" style={[palError.text, s.bold]}>
-                SANDBOX. Posts and accounts are not permanent.
+                <Trans>SANDBOX. Posts and accounts are not permanent.</Trans>
               </Text>
             </View>
           ) : undefined}
diff --git a/src/view/shell/desktop/Search.tsx b/src/view/shell/desktop/Search.tsx
index 6201f828f..f2a3de424 100644
--- a/src/view/shell/desktop/Search.tsx
+++ b/src/view/shell/desktop/Search.tsx
@@ -176,7 +176,7 @@ export function DesktopSearch() {
                 onPress={onPressCancelSearch}
                 accessibilityRole="button"
                 accessibilityLabel={_(msg`Cancel search`)}
-                accessibilityHint="Exits inputting search query"
+                accessibilityHint={_(msg`Exits inputting search query`)}
                 onAccessibilityEscape={onPressCancelSearch}>
                 <Text type="lg" style={[pal.link]}>
                   <Trans>Cancel</Trans>
diff --git a/src/view/shell/index.web.tsx b/src/view/shell/index.web.tsx
index 38da860bd..20bc0dff1 100644
--- a/src/view/shell/index.web.tsx
+++ b/src/view/shell/index.web.tsx
@@ -47,7 +47,7 @@ function ShellInner() {
           onPress={() => setDrawerOpen(false)}
           style={styles.drawerMask}
           accessibilityLabel={t`Close navigation footer`}
-          accessibilityHint="Closes bottom navigation bar">
+          accessibilityHint={t`Closes bottom navigation bar`}>
           <View style={styles.drawerContainer}>
             <DrawerContent />
           </View>