diff options
author | Stanislas Signoud <signez@stanisoft.net> | 2024-12-31 22:27:14 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-12-31 13:27:14 -0800 |
commit | 9f075b13405c7711edbd9309ab521738b74a50c5 (patch) | |
tree | 33acdca882ef027bc670bb38de3a9d054f6ce721 /src | |
parent | 09297d92cb73fcf3b7eda7d683543661d3f30501 (diff) | |
download | voidsky-9f075b13405c7711edbd9309ab521738b74a50c5.tar.zst |
Localize lang selectors according to the app language (#6207)
* Localize lang selectors according to the app language * Explicitly ignore RangeError when translating locale names
Diffstat (limited to 'src')
-rw-r--r-- | src/locale/helpers.ts | 42 | ||||
-rw-r--r-- | src/locale/languages.ts | 2 | ||||
-rw-r--r-- | src/screens/Settings/LanguageSettings.tsx | 8 | ||||
-rw-r--r-- | src/view/com/composer/select-language/SelectLangBtn.tsx | 6 | ||||
-rw-r--r-- | src/view/com/composer/select-language/SuggestedLanguage.tsx | 69 | ||||
-rw-r--r-- | src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx | 3 | ||||
-rw-r--r-- | src/view/com/modals/lang-settings/PostLanguagesSettings.tsx | 3 | ||||
-rw-r--r-- | src/view/screens/Search/Search.tsx | 9 |
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, |