about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEric Bailey <git@esb.lol>2024-01-30 17:04:54 -0600
committerGitHub <noreply@github.com>2024-01-30 15:04:54 -0800
commitbb7ce215f7d141ddefe6f259439d1169db46d594 (patch)
tree32597661cd71e2339b1ba75fbf6d1e131ef6feeb
parent4058174678e68a7536e772382be5f8f2a2b6e556 (diff)
downloadvoidsky-bb7ce215f7d141ddefe6f259439d1169db46d594.tar.zst
i18n interests, allow for fallbacks (#2692)
-rw-r--r--src/lib/strings/capitalize.ts3
-rw-r--r--src/screens/Onboarding/StepInterests/InterestButton.tsx6
-rw-r--r--src/screens/Onboarding/StepInterests/data.ts36
-rw-r--r--src/screens/Onboarding/StepInterests/index.tsx13
-rw-r--r--src/screens/Onboarding/StepSuggestedAccounts/index.tsx8
-rw-r--r--src/screens/Onboarding/StepTopicalFeeds.tsx8
-rw-r--r--src/screens/Onboarding/index.tsx35
-rw-r--r--src/screens/Onboarding/state.ts40
-rw-r--r--src/screens/Onboarding/util.ts10
9 files changed, 103 insertions, 56 deletions
diff --git a/src/lib/strings/capitalize.ts b/src/lib/strings/capitalize.ts
new file mode 100644
index 000000000..a3415bd00
--- /dev/null
+++ b/src/lib/strings/capitalize.ts
@@ -0,0 +1,3 @@
+export function capitalize(str: string) {
+  return str.charAt(0).toUpperCase() + str.slice(1)
+}
diff --git a/src/screens/Onboarding/StepInterests/InterestButton.tsx b/src/screens/Onboarding/StepInterests/InterestButton.tsx
index 02413b18d..cc692dafd 100644
--- a/src/screens/Onboarding/StepInterests/InterestButton.tsx
+++ b/src/screens/Onboarding/StepInterests/InterestButton.tsx
@@ -4,11 +4,13 @@ import {View, ViewStyle, TextStyle} from 'react-native'
 import {useTheme, atoms as a, native} from '#/alf'
 import * as Toggle from '#/components/forms/Toggle'
 import {Text} from '#/components/Typography'
+import {capitalize} from '#/lib/strings/capitalize'
 
-import {INTEREST_TO_DISPLAY_NAME} from '#/screens/Onboarding/StepInterests/data'
+import {Context} from '#/screens/Onboarding/state'
 
 export function InterestButton({interest}: {interest: string}) {
   const t = useTheme()
+  const {interestsDisplayNames} = React.useContext(Context)
   const ctx = Toggle.useItemContext()
 
   const styles = React.useMemo(() => {
@@ -72,7 +74,7 @@ export function InterestButton({interest}: {interest: string}) {
           native({paddingTop: 2}),
           ctx.selected ? styles.textSelected : {},
         ]}>
-        {INTEREST_TO_DISPLAY_NAME[interest]}
+        {interestsDisplayNames[interest] || capitalize(interest)}
       </Text>
     </View>
   )
diff --git a/src/screens/Onboarding/StepInterests/data.ts b/src/screens/Onboarding/StepInterests/data.ts
deleted file mode 100644
index 00a25331c..000000000
--- a/src/screens/Onboarding/StepInterests/data.ts
+++ /dev/null
@@ -1,36 +0,0 @@
-export const INTEREST_TO_DISPLAY_NAME: {
-  [key: string]: string
-} = {
-  news: 'News',
-  journalism: 'Journalism',
-  nature: 'Nature',
-  art: 'Art',
-  comics: 'Comics',
-  writers: 'Writers',
-  culture: 'Culture',
-  sports: 'Sports',
-  pets: 'Pets',
-  animals: 'Animals',
-  books: 'Books',
-  education: 'Education',
-  climate: 'Climate',
-  science: 'Science',
-  politics: 'Politics',
-  fitness: 'Fitness',
-  tech: 'Tech',
-  dev: 'Software Dev',
-  comedy: 'Comedy',
-  gaming: 'Video Games',
-  food: 'Food',
-  cooking: 'Cooking',
-}
-
-export type ApiResponseMap = {
-  interests: string[]
-  suggestedAccountDids: {
-    [key: string]: string[]
-  }
-  suggestedFeedUris: {
-    [key: string]: string[]
-  }
-}
diff --git a/src/screens/Onboarding/StepInterests/index.tsx b/src/screens/Onboarding/StepInterests/index.tsx
index 6f60991d5..5440dcd2b 100644
--- a/src/screens/Onboarding/StepInterests/index.tsx
+++ b/src/screens/Onboarding/StepInterests/index.tsx
@@ -17,17 +17,14 @@ import {getAgent} from '#/state/session'
 import {useAnalytics} from '#/lib/analytics/analytics'
 import {Text} from '#/components/Typography'
 import {useOnboardingDispatch} from '#/state/shell'
+import {capitalize} from '#/lib/strings/capitalize'
 
-import {Context} from '#/screens/Onboarding/state'
+import {Context, ApiResponseMap} from '#/screens/Onboarding/state'
 import {
   Title,
   Description,
   OnboardingControls,
 } from '#/screens/Onboarding/Layout'
-import {
-  ApiResponseMap,
-  INTEREST_TO_DISPLAY_NAME,
-} from '#/screens/Onboarding/StepInterests/data'
 import {InterestButton} from '#/screens/Onboarding/StepInterests/InterestButton'
 import {IconCircle} from '#/screens/Onboarding/IconCircle'
 
@@ -36,7 +33,7 @@ export function StepInterests() {
   const t = useTheme()
   const {track} = useAnalytics()
   const {gtMobile} = useBreakpoints()
-  const {state, dispatch} = React.useContext(Context)
+  const {state, dispatch, interestsDisplayNames} = React.useContext(Context)
   const [saving, setSaving] = React.useState(false)
   const [interests, setInterests] = React.useState<string[]>(
     state.interestsStepResults.selectedInterests.map(i => i),
@@ -202,7 +199,9 @@ export function StepInterests() {
                 <Toggle.Item
                   key={interest}
                   name={interest}
-                  label={INTEREST_TO_DISPLAY_NAME[interest]}>
+                  label={
+                    interestsDisplayNames[interest] || capitalize(interest)
+                  }>
                   <InterestButton interest={interest} />
                 </Toggle.Item>
               ))}
diff --git a/src/screens/Onboarding/StepSuggestedAccounts/index.tsx b/src/screens/Onboarding/StepSuggestedAccounts/index.tsx
index d3831791c..cf1f82559 100644
--- a/src/screens/Onboarding/StepSuggestedAccounts/index.tsx
+++ b/src/screens/Onboarding/StepSuggestedAccounts/index.tsx
@@ -14,6 +14,7 @@ import {Loader} from '#/components/Loader'
 import * as Toggle from '#/components/forms/Toggle'
 import {useModerationOpts} from '#/state/queries/preferences'
 import {useAnalytics} from '#/lib/analytics/analytics'
+import {capitalize} from '#/lib/strings/capitalize'
 
 import {Context} from '#/screens/Onboarding/state'
 import {
@@ -25,7 +26,6 @@ import {
   SuggestedAccountCard,
   SuggestedAccountCardPlaceholder,
 } from '#/screens/Onboarding/StepSuggestedAccounts/SuggestedAccountCard'
-import {INTEREST_TO_DISPLAY_NAME} from '#/screens/Onboarding/StepInterests/data'
 import {aggregateInterestItems} from '#/screens/Onboarding/util'
 import {IconCircle} from '#/screens/Onboarding/IconCircle'
 
@@ -70,7 +70,7 @@ export function Inner({
 export function StepSuggestedAccounts() {
   const {_} = useLingui()
   const {track} = useAnalytics()
-  const {state, dispatch} = React.useContext(Context)
+  const {state, dispatch, interestsDisplayNames} = React.useContext(Context)
   const {gtMobile} = useBreakpoints()
   const suggestedDids = React.useMemo(() => {
     return aggregateInterestItems(
@@ -93,10 +93,10 @@ export function StepSuggestedAccounts() {
 
   const interestsText = React.useMemo(() => {
     const i = state.interestsStepResults.selectedInterests.map(
-      i => INTEREST_TO_DISPLAY_NAME[i],
+      i => interestsDisplayNames[i] || capitalize(i),
     )
     return i.join(', ')
-  }, [state.interestsStepResults.selectedInterests])
+  }, [state.interestsStepResults.selectedInterests, interestsDisplayNames])
 
   const handleContinue = React.useCallback(async () => {
     setSaving(true)
diff --git a/src/screens/Onboarding/StepTopicalFeeds.tsx b/src/screens/Onboarding/StepTopicalFeeds.tsx
index 516c18e6e..ef77cc128 100644
--- a/src/screens/Onboarding/StepTopicalFeeds.tsx
+++ b/src/screens/Onboarding/StepTopicalFeeds.tsx
@@ -10,6 +10,7 @@ import {Button, ButtonIcon, ButtonText} from '#/components/Button'
 import * as Toggle from '#/components/forms/Toggle'
 import {Loader} from '#/components/Loader'
 import {useAnalytics} from '#/lib/analytics/analytics'
+import {capitalize} from '#/lib/strings/capitalize'
 
 import {Context} from '#/screens/Onboarding/state'
 import {
@@ -18,14 +19,13 @@ import {
   OnboardingControls,
 } from '#/screens/Onboarding/Layout'
 import {FeedCard} from '#/screens/Onboarding/StepAlgoFeeds/FeedCard'
-import {INTEREST_TO_DISPLAY_NAME} from '#/screens/Onboarding/StepInterests/data'
 import {aggregateInterestItems} from '#/screens/Onboarding/util'
 import {IconCircle} from '#/screens/Onboarding/IconCircle'
 
 export function StepTopicalFeeds() {
   const {_} = useLingui()
   const {track} = useAnalytics()
-  const {state, dispatch} = React.useContext(Context)
+  const {state, dispatch, interestsDisplayNames} = React.useContext(Context)
   const [selectedFeedUris, setSelectedFeedUris] = React.useState<string[]>([])
   const [saving, setSaving] = React.useState(false)
   const suggestedFeedUris = React.useMemo(() => {
@@ -38,10 +38,10 @@ export function StepTopicalFeeds() {
 
   const interestsText = React.useMemo(() => {
     const i = state.interestsStepResults.selectedInterests.map(
-      i => INTEREST_TO_DISPLAY_NAME[i],
+      i => interestsDisplayNames[i] || capitalize(i),
     )
     return i.join(', ')
-  }, [state.interestsStepResults.selectedInterests])
+  }, [state.interestsStepResults.selectedInterests, interestsDisplayNames])
 
   const saveFeeds = React.useCallback(async () => {
     setSaving(true)
diff --git a/src/screens/Onboarding/index.tsx b/src/screens/Onboarding/index.tsx
index a4eb04012..9e5029e87 100644
--- a/src/screens/Onboarding/index.tsx
+++ b/src/screens/Onboarding/index.tsx
@@ -1,4 +1,6 @@
 import React from 'react'
+import {useLingui} from '@lingui/react'
+import {msg} from '@lingui/macro'
 
 import {Portal} from '#/components/Portal'
 
@@ -13,13 +15,44 @@ import {StepFinished} from '#/screens/Onboarding/StepFinished'
 import {StepModeration} from '#/screens/Onboarding/StepModeration'
 
 export function Onboarding() {
+  const {_} = useLingui()
   const [state, dispatch] = React.useReducer(reducer, {...initialState})
 
+  const interestsDisplayNames = React.useMemo(() => {
+    return {
+      news: _(msg`News`),
+      journalism: _(msg`Journalism`),
+      nature: _(msg`Nature`),
+      art: _(msg`Art`),
+      comics: _(msg`Comics`),
+      writers: _(msg`Writers`),
+      culture: _(msg`Culture`),
+      sports: _(msg`Sports`),
+      pets: _(msg`Pets`),
+      animals: _(msg`Animals`),
+      books: _(msg`Books`),
+      education: _(msg`Education`),
+      climate: _(msg`Climate`),
+      science: _(msg`Science`),
+      politics: _(msg`Politics`),
+      fitness: _(msg`Fitness`),
+      tech: _(msg`Tech`),
+      dev: _(msg`Software Dev`),
+      comedy: _(msg`Comedy`),
+      gaming: _(msg`Video Games`),
+      food: _(msg`Food`),
+      cooking: _(msg`Cooking`),
+    }
+  }, [_])
+
   return (
     <Portal>
       <OnboardingControls.Provider>
         <Context.Provider
-          value={React.useMemo(() => ({state, dispatch}), [state, dispatch])}>
+          value={React.useMemo(
+            () => ({state, dispatch, interestsDisplayNames}),
+            [state, dispatch, interestsDisplayNames],
+          )}>
           <Layout>
             {state.activeStep === 'interests' && <StepInterests />}
             {state.activeStep === 'suggestedAccounts' && (
diff --git a/src/screens/Onboarding/state.ts b/src/screens/Onboarding/state.ts
index 164c2f5f3..bd8205ca2 100644
--- a/src/screens/Onboarding/state.ts
+++ b/src/screens/Onboarding/state.ts
@@ -1,6 +1,5 @@
 import React from 'react'
 
-import {ApiResponseMap} from '#/screens/Onboarding/StepInterests/data'
 import {logger} from '#/logger'
 
 export type OnboardingState = {
@@ -59,6 +58,16 @@ export type OnboardingAction =
       feedUris: string[]
     }
 
+export type ApiResponseMap = {
+  interests: string[]
+  suggestedAccountDids: {
+    [key: string]: string[]
+  }
+  suggestedFeedUris: {
+    [key: string]: string[]
+  }
+}
+
 export const initialState: OnboardingState = {
   hasPrev: false,
   totalSteps: 7,
@@ -84,12 +93,41 @@ export const initialState: OnboardingState = {
   },
 }
 
+export const INTEREST_TO_DISPLAY_NAME_DEFAULTS: {
+  [key: string]: string
+} = {
+  news: 'News',
+  journalism: 'Journalism',
+  nature: 'Nature',
+  art: 'Art',
+  comics: 'Comics',
+  writers: 'Writers',
+  culture: 'Culture',
+  sports: 'Sports',
+  pets: 'Pets',
+  animals: 'Animals',
+  books: 'Books',
+  education: 'Education',
+  climate: 'Climate',
+  science: 'Science',
+  politics: 'Politics',
+  fitness: 'Fitness',
+  tech: 'Tech',
+  dev: 'Software Dev',
+  comedy: 'Comedy',
+  gaming: 'Video Games',
+  food: 'Food',
+  cooking: 'Cooking',
+}
+
 export const Context = React.createContext<{
   state: OnboardingState
   dispatch: React.Dispatch<OnboardingAction>
+  interestsDisplayNames: {[key: string]: string}
 }>({
   state: {...initialState},
   dispatch: () => {},
+  interestsDisplayNames: INTEREST_TO_DISPLAY_NAME_DEFAULTS,
 })
 
 export function reducer(
diff --git a/src/screens/Onboarding/util.ts b/src/screens/Onboarding/util.ts
index 2a709a67b..eae661aa4 100644
--- a/src/screens/Onboarding/util.ts
+++ b/src/screens/Onboarding/util.ts
@@ -31,7 +31,15 @@ export function aggregateInterestItems(
   const selected = interests.length
   const all = interests
     .map(i => {
-      const suggestions = shuffle(map[i])
+      // suggestions from server
+      const rawSuggestions = map[i]
+
+      // safeguard against a missing interest->suggestion mapping
+      if (!rawSuggestions || !rawSuggestions.length) {
+        return []
+      }
+
+      const suggestions = shuffle(rawSuggestions)
 
       if (selected === 1) {
         return suggestions // return all