Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Localize lang selectors according to the app language (#6207)

* Localize lang selectors according to the app language

* Explicitly ignore RangeError when translating locale names

authored by

Stanislas Signoud and committed by
GitHub
9f075b13 09297d92

+97 -45
+39 -3
src/locale/helpers.ts
··· 5 5 import {hasProp} from '#/lib/type-guards' 6 6 import { 7 7 AppLanguage, 8 + type Language, 8 9 LANGUAGES_MAP_CODE2, 9 10 LANGUAGES_MAP_CODE3, 10 11 } from './languages' ··· 31 32 return undefined 32 33 } 33 34 34 - export function codeToLanguageName(lang: string): string { 35 - const lang2 = code3ToCode2(lang) 36 - return LANGUAGES_MAP_CODE2[lang2]?.name || lang 35 + function getLocalizedLanguage( 36 + langCode: string, 37 + appLang: string, 38 + ): string | undefined { 39 + try { 40 + const allNames = new Intl.DisplayNames([appLang], { 41 + type: 'language', 42 + fallback: 'none', 43 + languageDisplay: 'standard', 44 + }) 45 + const translatedName = allNames.of(langCode) 46 + 47 + if (translatedName) { 48 + // force simple title case (as languages do not always start with an uppercase in Unicode data) 49 + return translatedName[0].toLocaleUpperCase() + translatedName.slice(1) 50 + } 51 + } catch (e) { 52 + // ignore RangeError from Intl.DisplayNames APIs 53 + if (!(e instanceof RangeError)) { 54 + throw e 55 + } 56 + } 57 + } 58 + 59 + export function languageName(language: Language, appLang: string): string { 60 + // if Intl.DisplayNames is unavailable on the target, display the English name 61 + if (!(Intl as any).DisplayNames) { 62 + return language.name 63 + } 64 + 65 + return getLocalizedLanguage(language.code2, appLang) || language.name 66 + } 67 + 68 + export function codeToLanguageName(lang2or3: string, appLang: string): string { 69 + const code2 = code3ToCode2(lang2or3) 70 + const knownLanguage = LANGUAGES_MAP_CODE2[code2] 71 + 72 + return knownLanguage ? languageName(knownLanguage, appLang) : code2 37 73 } 38 74 39 75 export function getPostLanguage(
+1 -1
src/locale/languages.ts
··· 1 - interface Language { 1 + export interface Language { 2 2 code3: string 3 3 code2: string 4 4 name: string
+4 -4
src/screens/Settings/LanguageSettings.tsx
··· 6 6 7 7 import {APP_LANGUAGES, LANGUAGES} from '#/lib/../locale/languages' 8 8 import {CommonNavigatorParams, NativeStackScreenProps} from '#/lib/routes/types' 9 - import {sanitizeAppLanguageSetting} from '#/locale/helpers' 9 + import {languageName, sanitizeAppLanguageSetting} from '#/locale/helpers' 10 10 import {useModalControls} from '#/state/modals' 11 11 import {useLanguagePrefs, useLanguagePrefsApi} from '#/state/preferences' 12 12 import {atoms as a, useTheme, web} from '#/alf' ··· 57 57 .map(lang => LANGUAGES.find(l => l.code2 === lang)) 58 58 .filter(Boolean) 59 59 // @ts-ignore 60 - .map(l => l.name) 60 + .map(l => languageName(l, langPrefs.appLanguage)) 61 61 .join(', ') 62 62 ) 63 - }, [langPrefs.contentLanguages]) 63 + }, [langPrefs.appLanguage, langPrefs.contentLanguages]) 64 64 65 65 return ( 66 66 <Layout.Screen testID="PreferencesLanguagesScreen"> ··· 179 179 value={langPrefs.primaryLanguage} 180 180 onValueChange={onChangePrimaryLanguage} 181 181 items={LANGUAGES.filter(l => Boolean(l.code2)).map(l => ({ 182 - label: l.name, 182 + label: languageName(l, langPrefs.appLanguage), 183 183 value: l.code2, 184 184 key: l.code2 + l.code3, 185 185 }))}
+4 -2
src/view/com/composer/select-language/SelectLangBtn.tsx
··· 48 48 function add(commaSeparatedLangCodes: string) { 49 49 const langCodes = commaSeparatedLangCodes.split(',') 50 50 const langName = langCodes 51 - .map(code => codeToLanguageName(code)) 51 + .map(code => codeToLanguageName(code, langPrefs.appLanguage)) 52 52 .join(' + ') 53 53 54 54 /* ··· 108 108 accessibilityHint=""> 109 109 {postLanguagesPref.length > 0 ? ( 110 110 <Text type="lg-bold" style={[pal.link, styles.label]} numberOfLines={1}> 111 - {postLanguagesPref.map(lang => codeToLanguageName(lang)).join(', ')} 111 + {postLanguagesPref 112 + .map(lang => codeToLanguageName(lang, langPrefs.appLanguage)) 113 + .join(', ')} 112 114 </Text> 113 115 ) : ( 114 116 <FontAwesomeIcon
+40 -29
src/view/com/composer/select-language/SuggestedLanguage.tsx
··· 49 49 return () => cancelIdle(idle) 50 50 }, [text]) 51 51 52 - return suggestedLanguage && 53 - !toPostLanguages(langPrefs.postLanguage).includes(suggestedLanguage) ? ( 54 - <View style={[pal.border, styles.infoBar]}> 55 - <FontAwesomeIcon 56 - icon="language" 57 - style={pal.text as FontAwesomeIconStyle} 58 - size={24} 59 - /> 60 - <Text style={[pal.text, s.flex1]}> 61 - <Trans> 62 - Are you writing in{' '} 63 - <Text type="sm-bold" style={pal.text}> 64 - {codeToLanguageName(suggestedLanguage)} 65 - </Text> 66 - ? 67 - </Trans> 68 - </Text> 52 + if ( 53 + suggestedLanguage && 54 + !toPostLanguages(langPrefs.postLanguage).includes(suggestedLanguage) 55 + ) { 56 + const suggestedLanguageName = codeToLanguageName( 57 + suggestedLanguage, 58 + langPrefs.appLanguage, 59 + ) 69 60 70 - <Button 71 - type="default" 72 - onPress={() => setLangPrefs.setPostLanguage(suggestedLanguage)} 73 - accessibilityLabel={_( 74 - msg`Change post language to ${codeToLanguageName(suggestedLanguage)}`, 75 - )} 76 - accessibilityHint=""> 77 - <Text type="button" style={[pal.link, s.fw600]}> 78 - <Trans>Yes</Trans> 61 + return ( 62 + <View style={[pal.border, styles.infoBar]}> 63 + <FontAwesomeIcon 64 + icon="language" 65 + style={pal.text as FontAwesomeIconStyle} 66 + size={24} 67 + /> 68 + <Text style={[pal.text, s.flex1]}> 69 + <Trans> 70 + Are you writing in{' '} 71 + <Text type="sm-bold" style={pal.text}> 72 + {suggestedLanguageName} 73 + </Text> 74 + ? 75 + </Trans> 79 76 </Text> 80 - </Button> 81 - </View> 82 - ) : null 77 + 78 + <Button 79 + type="default" 80 + onPress={() => setLangPrefs.setPostLanguage(suggestedLanguage)} 81 + accessibilityLabel={_( 82 + msg`Change post language to ${suggestedLanguageName}`, 83 + )} 84 + accessibilityHint=""> 85 + <Text type="button" style={[pal.link, s.fw600]}> 86 + <Trans>Yes</Trans> 87 + </Text> 88 + </Button> 89 + </View> 90 + ) 91 + } else { 92 + return null 93 + } 83 94 } 84 95 85 96 const styles = StyleSheet.create({
+2 -1
src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx
··· 5 5 import {usePalette} from '#/lib/hooks/usePalette' 6 6 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 7 7 import {deviceLanguageCodes} from '#/locale/deviceLocales' 8 + import {languageName} from '#/locale/helpers' 8 9 import {useModalControls} from '#/state/modals' 9 10 import { 10 11 useLanguagePrefs, ··· 88 89 key={lang.code2} 89 90 code2={lang.code2} 90 91 langType="contentLanguages" 91 - name={lang.name} 92 + name={languageName(lang, langPrefs.appLanguage)} 92 93 onPress={() => { 93 94 onPress(lang.code2) 94 95 }}
+2 -1
src/view/com/modals/lang-settings/PostLanguagesSettings.tsx
··· 5 5 import {usePalette} from '#/lib/hooks/usePalette' 6 6 import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 7 7 import {deviceLanguageCodes} from '#/locale/deviceLocales' 8 + import {languageName} from '#/locale/helpers' 8 9 import {useModalControls} from '#/state/modals' 9 10 import { 10 11 hasPostLanguage, ··· 91 92 return ( 92 93 <ToggleButton 93 94 key={lang.code2} 94 - label={lang.name} 95 + label={languageName(lang, langPrefs.appLanguage)} 95 96 isSelected={isSelected} 96 97 onPress={() => (isDisabled ? undefined : onPress(lang.code2))} 97 98 style={[
+5 -4
src/view/screens/Search/Search.tsx
··· 37 37 } from '#/lib/routes/types' 38 38 import {sanitizeDisplayName} from '#/lib/strings/display-names' 39 39 import {augmentSearchQuery} from '#/lib/strings/helpers' 40 + import {languageName} from '#/locale/helpers' 40 41 import {logger} from '#/logger' 41 42 import {isNative, isWeb} from '#/platform/detection' 42 43 import {listenSoftReset} from '#/state/events' ··· 328 329 }) { 329 330 const t = useThemeNew() 330 331 const {_} = useLingui() 331 - const {contentLanguages} = useLanguagePrefs() 332 + const {appLanguage, contentLanguages} = useLanguagePrefs() 332 333 333 334 const items = React.useMemo(() => { 334 335 return [ ··· 345 346 index === self.findIndex(t => t.code2 === lang.code2), // remove dupes (which will happen) 346 347 ) 347 348 .map(l => ({ 348 - label: l.name, 349 - inputLabel: l.name, 349 + label: languageName(l, appLanguage), 350 + inputLabel: languageName(l, appLanguage), 350 351 value: l.code2, 351 352 key: l.code2 + l.code3, 352 353 })) ··· 365 366 return a.label.localeCompare(b.label) 366 367 }), 367 368 ) 368 - }, [_, contentLanguages]) 369 + }, [_, appLanguage, contentLanguages]) 369 370 370 371 const style = { 371 372 backgroundColor: t.atoms.bg_contrast_25.backgroundColor,