about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/locale/helpers.ts42
-rw-r--r--src/locale/languages.ts2
-rw-r--r--src/screens/Settings/LanguageSettings.tsx8
-rw-r--r--src/view/com/composer/select-language/SelectLangBtn.tsx6
-rw-r--r--src/view/com/composer/select-language/SuggestedLanguage.tsx69
-rw-r--r--src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx3
-rw-r--r--src/view/com/modals/lang-settings/PostLanguagesSettings.tsx3
-rw-r--r--src/view/screens/Search/Search.tsx9
8 files changed, 97 insertions, 45 deletions
diff --git a/src/locale/helpers.ts b/src/locale/helpers.ts
index c469b3c58..94e9d4327 100644
--- a/src/locale/helpers.ts
+++ b/src/locale/helpers.ts
@@ -5,6 +5,7 @@ import lande from 'lande'
 import {hasProp} from '#/lib/type-guards'
 import {
   AppLanguage,
+  type Language,
   LANGUAGES_MAP_CODE2,
   LANGUAGES_MAP_CODE3,
 } from './languages'
@@ -31,9 +32,44 @@ export function code3ToCode2Strict(lang: string): string | undefined {
   return undefined
 }
 
-export function codeToLanguageName(lang: string): string {
-  const lang2 = code3ToCode2(lang)
-  return LANGUAGES_MAP_CODE2[lang2]?.name || lang
+function getLocalizedLanguage(
+  langCode: string,
+  appLang: string,
+): string | undefined {
+  try {
+    const allNames = new Intl.DisplayNames([appLang], {
+      type: 'language',
+      fallback: 'none',
+      languageDisplay: 'standard',
+    })
+    const translatedName = allNames.of(langCode)
+
+    if (translatedName) {
+      // force simple title case (as languages do not always start with an uppercase in Unicode data)
+      return translatedName[0].toLocaleUpperCase() + translatedName.slice(1)
+    }
+  } catch (e) {
+    // ignore RangeError from Intl.DisplayNames APIs
+    if (!(e instanceof RangeError)) {
+      throw e
+    }
+  }
+}
+
+export function languageName(language: Language, appLang: string): string {
+  // if Intl.DisplayNames is unavailable on the target, display the English name
+  if (!(Intl as any).DisplayNames) {
+    return language.name
+  }
+
+  return getLocalizedLanguage(language.code2, appLang) || language.name
+}
+
+export function codeToLanguageName(lang2or3: string, appLang: string): string {
+  const code2 = code3ToCode2(lang2or3)
+  const knownLanguage = LANGUAGES_MAP_CODE2[code2]
+
+  return knownLanguage ? languageName(knownLanguage, appLang) : code2
 }
 
 export function getPostLanguage(
diff --git a/src/locale/languages.ts b/src/locale/languages.ts
index 6ac601dea..9f599c8c8 100644
--- a/src/locale/languages.ts
+++ b/src/locale/languages.ts
@@ -1,4 +1,4 @@
-interface Language {
+export interface Language {
   code3: string
   code2: string
   name: string
diff --git a/src/screens/Settings/LanguageSettings.tsx b/src/screens/Settings/LanguageSettings.tsx
index 096f92566..8fece7129 100644
--- a/src/screens/Settings/LanguageSettings.tsx
+++ b/src/screens/Settings/LanguageSettings.tsx
@@ -6,7 +6,7 @@ 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 {languageName, sanitizeAppLanguageSetting} from '#/locale/helpers'
 import {useModalControls} from '#/state/modals'
 import {useLanguagePrefs, useLanguagePrefsApi} from '#/state/preferences'
 import {atoms as a, useTheme, web} from '#/alf'
@@ -57,10 +57,10 @@ export function LanguageSettingsScreen({}: Props) {
         .map(lang => LANGUAGES.find(l => l.code2 === lang))
         .filter(Boolean)
         // @ts-ignore
-        .map(l => l.name)
+        .map(l => languageName(l, langPrefs.appLanguage))
         .join(', ')
     )
-  }, [langPrefs.contentLanguages])
+  }, [langPrefs.appLanguage, langPrefs.contentLanguages])
 
   return (
     <Layout.Screen testID="PreferencesLanguagesScreen">
@@ -179,7 +179,7 @@ export function LanguageSettingsScreen({}: Props) {
                   value={langPrefs.primaryLanguage}
                   onValueChange={onChangePrimaryLanguage}
                   items={LANGUAGES.filter(l => Boolean(l.code2)).map(l => ({
-                    label: l.name,
+                    label: languageName(l, langPrefs.appLanguage),
                     value: l.code2,
                     key: l.code2 + l.code3,
                   }))}
diff --git a/src/view/com/composer/select-language/SelectLangBtn.tsx b/src/view/com/composer/select-language/SelectLangBtn.tsx
index cd3cb608d..f487b1244 100644
--- a/src/view/com/composer/select-language/SelectLangBtn.tsx
+++ b/src/view/com/composer/select-language/SelectLangBtn.tsx
@@ -48,7 +48,7 @@ export function SelectLangBtn() {
     function add(commaSeparatedLangCodes: string) {
       const langCodes = commaSeparatedLangCodes.split(',')
       const langName = langCodes
-        .map(code => codeToLanguageName(code))
+        .map(code => codeToLanguageName(code, langPrefs.appLanguage))
         .join(' + ')
 
       /*
@@ -108,7 +108,9 @@ export function SelectLangBtn() {
       accessibilityHint="">
       {postLanguagesPref.length > 0 ? (
         <Text type="lg-bold" style={[pal.link, styles.label]} numberOfLines={1}>
-          {postLanguagesPref.map(lang => codeToLanguageName(lang)).join(', ')}
+          {postLanguagesPref
+            .map(lang => codeToLanguageName(lang, langPrefs.appLanguage))
+            .join(', ')}
         </Text>
       ) : (
         <FontAwesomeIcon
diff --git a/src/view/com/composer/select-language/SuggestedLanguage.tsx b/src/view/com/composer/select-language/SuggestedLanguage.tsx
index 6d55aeb53..472860a32 100644
--- a/src/view/com/composer/select-language/SuggestedLanguage.tsx
+++ b/src/view/com/composer/select-language/SuggestedLanguage.tsx
@@ -49,37 +49,48 @@ export function SuggestedLanguage({text}: {text: string}) {
     return () => cancelIdle(idle)
   }, [text])
 
-  return suggestedLanguage &&
-    !toPostLanguages(langPrefs.postLanguage).includes(suggestedLanguage) ? (
-    <View style={[pal.border, styles.infoBar]}>
-      <FontAwesomeIcon
-        icon="language"
-        style={pal.text as FontAwesomeIconStyle}
-        size={24}
-      />
-      <Text style={[pal.text, s.flex1]}>
-        <Trans>
-          Are you writing in{' '}
-          <Text type="sm-bold" style={pal.text}>
-            {codeToLanguageName(suggestedLanguage)}
-          </Text>
-          ?
-        </Trans>
-      </Text>
+  if (
+    suggestedLanguage &&
+    !toPostLanguages(langPrefs.postLanguage).includes(suggestedLanguage)
+  ) {
+    const suggestedLanguageName = codeToLanguageName(
+      suggestedLanguage,
+      langPrefs.appLanguage,
+    )
 
-      <Button
-        type="default"
-        onPress={() => setLangPrefs.setPostLanguage(suggestedLanguage)}
-        accessibilityLabel={_(
-          msg`Change post language to ${codeToLanguageName(suggestedLanguage)}`,
-        )}
-        accessibilityHint="">
-        <Text type="button" style={[pal.link, s.fw600]}>
-          <Trans>Yes</Trans>
+    return (
+      <View style={[pal.border, styles.infoBar]}>
+        <FontAwesomeIcon
+          icon="language"
+          style={pal.text as FontAwesomeIconStyle}
+          size={24}
+        />
+        <Text style={[pal.text, s.flex1]}>
+          <Trans>
+            Are you writing in{' '}
+            <Text type="sm-bold" style={pal.text}>
+              {suggestedLanguageName}
+            </Text>
+            ?
+          </Trans>
         </Text>
-      </Button>
-    </View>
-  ) : null
+
+        <Button
+          type="default"
+          onPress={() => setLangPrefs.setPostLanguage(suggestedLanguage)}
+          accessibilityLabel={_(
+            msg`Change post language to ${suggestedLanguageName}`,
+          )}
+          accessibilityHint="">
+          <Text type="button" style={[pal.link, s.fw600]}>
+            <Trans>Yes</Trans>
+          </Text>
+        </Button>
+      </View>
+    )
+  } else {
+    return null
+  }
 }
 
 const styles = StyleSheet.create({
diff --git a/src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx b/src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx
index 360cc0e40..aae8e29d6 100644
--- a/src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx
+++ b/src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx
@@ -5,6 +5,7 @@ import {Trans} from '@lingui/macro'
 import {usePalette} from '#/lib/hooks/usePalette'
 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
 import {deviceLanguageCodes} from '#/locale/deviceLocales'
+import {languageName} from '#/locale/helpers'
 import {useModalControls} from '#/state/modals'
 import {
   useLanguagePrefs,
@@ -88,7 +89,7 @@ export function Component({}: {}) {
             key={lang.code2}
             code2={lang.code2}
             langType="contentLanguages"
-            name={lang.name}
+            name={languageName(lang, langPrefs.appLanguage)}
             onPress={() => {
               onPress(lang.code2)
             }}
diff --git a/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx b/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx
index 2b0eb8cf2..8c2969674 100644
--- a/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx
+++ b/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx
@@ -5,6 +5,7 @@ import {Trans} from '@lingui/macro'
 import {usePalette} from '#/lib/hooks/usePalette'
 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
 import {deviceLanguageCodes} from '#/locale/deviceLocales'
+import {languageName} from '#/locale/helpers'
 import {useModalControls} from '#/state/modals'
 import {
   hasPostLanguage,
@@ -91,7 +92,7 @@ export function Component() {
           return (
             <ToggleButton
               key={lang.code2}
-              label={lang.name}
+              label={languageName(lang, langPrefs.appLanguage)}
               isSelected={isSelected}
               onPress={() => (isDisabled ? undefined : onPress(lang.code2))}
               style={[
diff --git a/src/view/screens/Search/Search.tsx b/src/view/screens/Search/Search.tsx
index 2797c9d95..2c91d37a2 100644
--- a/src/view/screens/Search/Search.tsx
+++ b/src/view/screens/Search/Search.tsx
@@ -37,6 +37,7 @@ import {
 } from '#/lib/routes/types'
 import {sanitizeDisplayName} from '#/lib/strings/display-names'
 import {augmentSearchQuery} from '#/lib/strings/helpers'
+import {languageName} from '#/locale/helpers'
 import {logger} from '#/logger'
 import {isNative, isWeb} from '#/platform/detection'
 import {listenSoftReset} from '#/state/events'
@@ -328,7 +329,7 @@ function SearchLanguageDropdown({
 }) {
   const t = useThemeNew()
   const {_} = useLingui()
-  const {contentLanguages} = useLanguagePrefs()
+  const {appLanguage, contentLanguages} = useLanguagePrefs()
 
   const items = React.useMemo(() => {
     return [
@@ -345,8 +346,8 @@ function SearchLanguageDropdown({
           index === self.findIndex(t => t.code2 === lang.code2), // remove dupes (which will happen)
       )
         .map(l => ({
-          label: l.name,
-          inputLabel: l.name,
+          label: languageName(l, appLanguage),
+          inputLabel: languageName(l, appLanguage),
           value: l.code2,
           key: l.code2 + l.code3,
         }))
@@ -365,7 +366,7 @@ function SearchLanguageDropdown({
           return a.label.localeCompare(b.label)
         }),
     )
-  }, [_, contentLanguages])
+  }, [_, appLanguage, contentLanguages])
 
   const style = {
     backgroundColor: t.atoms.bg_contrast_25.backgroundColor,