about summary refs log tree commit diff
path: root/src/screens/Settings/LanguageSettings.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/screens/Settings/LanguageSettings.tsx')
-rw-r--r--src/screens/Settings/LanguageSettings.tsx275
1 files changed, 275 insertions, 0 deletions
diff --git a/src/screens/Settings/LanguageSettings.tsx b/src/screens/Settings/LanguageSettings.tsx
new file mode 100644
index 000000000..c6cd8bb5a
--- /dev/null
+++ b/src/screens/Settings/LanguageSettings.tsx
@@ -0,0 +1,275 @@
+import React, {useCallback, useMemo} from 'react'
+import {View} from 'react-native'
+import RNPickerSelect, {PickerSelectProps} from 'react-native-picker-select'
+import {msg, Trans} from '@lingui/macro'
+import {useLingui} from '@lingui/react'
+
+import {APP_LANGUAGES, LANGUAGES} from '#/lib/../locale/languages'
+import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types'
+import {sanitizeAppLanguageSetting} from '#/locale/helpers'
+import {useModalControls} from '#/state/modals'
+import {useLanguagePrefs, useLanguagePrefsApi} from '#/state/preferences'
+import {atoms as a, useTheme, web} from '#/alf'
+import {Button, ButtonIcon, ButtonText} from '#/components/Button'
+import {Check_Stroke2_Corner0_Rounded as CheckIcon} from '#/components/icons/Check'
+import {ChevronBottom_Stroke2_Corner0_Rounded as ChevronDownIcon} from '#/components/icons/Chevron'
+import {PlusLarge_Stroke2_Corner0_Rounded as PlusIcon} from '#/components/icons/Plus'
+import * as Layout from '#/components/Layout'
+import {Text} from '#/components/Typography'
+import * as SettingsList from './components/SettingsList'
+
+type Props = NativeStackScreenProps<CommonNavigatorParams, 'LanguageSettings'>
+export function LanguageSettingsScreen({}: Props) {
+  const {_} = useLingui()
+  const langPrefs = useLanguagePrefs()
+  const setLangPrefs = useLanguagePrefsApi()
+  const t = useTheme()
+
+  const {openModal} = useModalControls()
+
+  const onPressContentLanguages = useCallback(() => {
+    openModal({name: 'content-languages-settings'})
+  }, [openModal])
+
+  const onChangePrimaryLanguage = useCallback(
+    (value: Parameters<PickerSelectProps['onValueChange']>[0]) => {
+      if (!value) return
+      if (langPrefs.primaryLanguage !== value) {
+        setLangPrefs.setPrimaryLanguage(value)
+      }
+    },
+    [langPrefs, setLangPrefs],
+  )
+
+  const onChangeAppLanguage = useCallback(
+    (value: Parameters<PickerSelectProps['onValueChange']>[0]) => {
+      if (!value) return
+      if (langPrefs.appLanguage !== value) {
+        setLangPrefs.setAppLanguage(sanitizeAppLanguageSetting(value))
+      }
+    },
+    [langPrefs, setLangPrefs],
+  )
+
+  const myLanguages = useMemo(() => {
+    return (
+      langPrefs.contentLanguages
+        .map(lang => LANGUAGES.find(l => l.code2 === lang))
+        .filter(Boolean)
+        // @ts-ignore
+        .map(l => l.name)
+        .join(', ')
+    )
+  }, [langPrefs.contentLanguages])
+
+  return (
+    <Layout.Screen testID="PreferencesLanguagesScreen">
+      <Layout.Header title={_(msg`Languages`)} />
+      <Layout.Content>
+        <SettingsList.Container>
+          <SettingsList.Group iconInset={false}>
+            <SettingsList.ItemText>
+              <Trans>App Language</Trans>
+            </SettingsList.ItemText>
+            <View style={[a.gap_md, a.w_full]}>
+              <Text style={[a.leading_snug]}>
+                <Trans>
+                  Select your app language for the default text to display in
+                  the app.
+                </Trans>
+              </Text>
+              <View style={[a.relative, web([a.w_full, {maxWidth: 400}])]}>
+                <RNPickerSelect
+                  placeholder={{}}
+                  value={sanitizeAppLanguageSetting(langPrefs.appLanguage)}
+                  onValueChange={onChangeAppLanguage}
+                  items={APP_LANGUAGES.filter(l => Boolean(l.code2)).map(l => ({
+                    label: l.name,
+                    value: l.code2,
+                    key: l.code2,
+                  }))}
+                  style={{
+                    inputAndroid: {
+                      backgroundColor: t.atoms.bg_contrast_25.backgroundColor,
+                      color: t.atoms.text.color,
+                      fontSize: 14,
+                      letterSpacing: 0.5,
+                      fontWeight: a.font_bold.fontWeight,
+                      paddingHorizontal: 14,
+                      paddingVertical: 8,
+                      borderRadius: a.rounded_xs.borderRadius,
+                    },
+                    inputIOS: {
+                      backgroundColor: t.atoms.bg_contrast_25.backgroundColor,
+                      color: t.atoms.text.color,
+                      fontSize: 14,
+                      letterSpacing: 0.5,
+                      fontWeight: a.font_bold.fontWeight,
+                      paddingHorizontal: 14,
+                      paddingVertical: 8,
+                      borderRadius: a.rounded_xs.borderRadius,
+                    },
+                    inputWeb: {
+                      flex: 1,
+                      width: '100%',
+                      cursor: 'pointer',
+                      // @ts-ignore web only
+                      '-moz-appearance': 'none',
+                      '-webkit-appearance': 'none',
+                      appearance: 'none',
+                      outline: 0,
+                      borderWidth: 0,
+                      backgroundColor: t.atoms.bg_contrast_25.backgroundColor,
+                      color: t.atoms.text.color,
+                      fontSize: 14,
+                      fontFamily: 'inherit',
+                      letterSpacing: 0.5,
+                      fontWeight: a.font_bold.fontWeight,
+                      paddingHorizontal: 14,
+                      paddingVertical: 8,
+                      borderRadius: a.rounded_xs.borderRadius,
+                    },
+                  }}
+                />
+
+                <View
+                  style={[
+                    a.absolute,
+                    t.atoms.bg_contrast_25,
+                    a.rounded_xs,
+                    a.pointer_events_none,
+                    a.align_center,
+                    a.justify_center,
+                    {
+                      top: 1,
+                      right: 1,
+                      bottom: 1,
+                      width: 40,
+                    },
+                  ]}>
+                  <ChevronDownIcon style={[t.atoms.text]} />
+                </View>
+              </View>
+            </View>
+          </SettingsList.Group>
+          <SettingsList.Divider />
+          <SettingsList.Group iconInset={false}>
+            <SettingsList.ItemText>
+              <Trans>Primary Language</Trans>
+            </SettingsList.ItemText>
+            <View style={[a.gap_md, a.w_full]}>
+              <Text style={[a.leading_snug]}>
+                <Trans>
+                  Select your preferred language for translations in your feed.
+                </Trans>
+              </Text>
+              <View style={[a.relative, web([a.w_full, {maxWidth: 400}])]}>
+                <RNPickerSelect
+                  placeholder={{}}
+                  value={langPrefs.primaryLanguage}
+                  onValueChange={onChangePrimaryLanguage}
+                  items={LANGUAGES.filter(l => Boolean(l.code2)).map(l => ({
+                    label: l.name,
+                    value: l.code2,
+                    key: l.code2 + l.code3,
+                  }))}
+                  style={{
+                    inputAndroid: {
+                      backgroundColor: t.atoms.bg_contrast_25.backgroundColor,
+                      color: t.atoms.text.color,
+                      fontSize: 14,
+                      letterSpacing: 0.5,
+                      fontWeight: a.font_bold.fontWeight,
+                      paddingHorizontal: 14,
+                      paddingVertical: 8,
+                      borderRadius: a.rounded_xs.borderRadius,
+                    },
+                    inputIOS: {
+                      backgroundColor: t.atoms.bg_contrast_25.backgroundColor,
+                      color: t.atoms.text.color,
+                      fontSize: 14,
+                      letterSpacing: 0.5,
+                      fontWeight: a.font_bold.fontWeight,
+                      paddingHorizontal: 14,
+                      paddingVertical: 8,
+                      borderRadius: a.rounded_xs.borderRadius,
+                    },
+                    inputWeb: {
+                      flex: 1,
+                      width: '100%',
+                      cursor: 'pointer',
+                      // @ts-ignore web only
+                      '-moz-appearance': 'none',
+                      '-webkit-appearance': 'none',
+                      appearance: 'none',
+                      outline: 0,
+                      borderWidth: 0,
+                      backgroundColor: t.atoms.bg_contrast_25.backgroundColor,
+                      color: t.atoms.text.color,
+                      fontSize: 14,
+                      fontFamily: 'inherit',
+                      letterSpacing: 0.5,
+                      fontWeight: a.font_bold.fontWeight,
+                      paddingHorizontal: 14,
+                      paddingVertical: 8,
+                      borderRadius: a.rounded_xs.borderRadius,
+                    },
+                  }}
+                />
+
+                <View
+                  style={{
+                    position: 'absolute',
+                    top: 1,
+                    right: 1,
+                    bottom: 1,
+                    width: 40,
+                    backgroundColor: t.atoms.bg_contrast_25.backgroundColor,
+                    borderRadius: a.rounded_xs.borderRadius,
+                    pointerEvents: 'none',
+                    alignItems: 'center',
+                    justifyContent: 'center',
+                  }}>
+                  <ChevronDownIcon style={t.atoms.text} />
+                </View>
+              </View>
+            </View>
+          </SettingsList.Group>
+          <SettingsList.Divider />
+          <SettingsList.Group iconInset={false}>
+            <SettingsList.ItemText>
+              <Trans>Content Languages</Trans>
+            </SettingsList.ItemText>
+            <View style={[a.gap_md]}>
+              <Text style={[a.leading_snug]}>
+                <Trans>
+                  Select which languages you want your subscribed feeds to
+                  include. If none are selected, all languages will be shown.
+                </Trans>
+              </Text>
+
+              <Button
+                label={_(msg`Select content languages`)}
+                size="small"
+                color="secondary"
+                variant="solid"
+                onPress={onPressContentLanguages}
+                style={[a.justify_start, web({maxWidth: 400})]}>
+                <ButtonIcon
+                  icon={myLanguages.length > 0 ? CheckIcon : PlusIcon}
+                />
+                <ButtonText
+                  style={[t.atoms.text, a.text_md, a.flex_1, a.text_left]}
+                  numberOfLines={1}>
+                  {myLanguages.length > 0
+                    ? myLanguages
+                    : _(msg`Select languages`)}
+                </ButtonText>
+              </Button>
+            </View>
+          </SettingsList.Group>
+        </SettingsList.Container>
+      </Layout.Content>
+    </Layout.Screen>
+  )
+}