From b74263e93d0b23f1befa07dc7c0c45a7eab60841 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Tue, 17 Sep 2024 08:52:38 -0500 Subject: [PATCH] Refactor --- src/locale/deviceLocales.ts | 51 +++++++++++++++++++ src/locale/helpers.ts | 7 ++- src/platform/detection.ts | 10 ---- src/state/persisted/schema.ts | 12 ++--- .../ContentLanguagesSettings.tsx | 21 ++++---- .../lang-settings/PostLanguagesSettings.tsx | 23 +++++---- 6 files changed, 86 insertions(+), 38 deletions(-) create mode 100644 src/locale/deviceLocales.ts diff --git a/src/locale/deviceLocales.ts b/src/locale/deviceLocales.ts new file mode 100644 index 0000000000..586553b66a --- /dev/null +++ b/src/locale/deviceLocales.ts @@ -0,0 +1,51 @@ +import {getLocales as defaultGetLocales, Locale} from 'expo-localization' + +import {dedupArray} from '#/lib/functions' + +type LocalWithLanguageCode = Locale & { + languageCode: string +} + +/** + * Normalized locales + * + * Handles legacy migration for Java devices. + * + * {@link https://github.com/bluesky-social/social-app/pull/4461} + * {@link https://xml.coverpages.org/iso639a.html} + */ +export function getLocales() { + const locales = defaultGetLocales?.() ?? [] + const output: LocalWithLanguageCode[] = [] + + for (const locale of locales) { + if (typeof locale.languageCode === 'string') { + if (locale.languageCode === 'in') { + // indonesian + locale.languageCode = 'id' + } + if (locale.languageCode === 'iw') { + // hebrew + locale.languageCode = 'he' + } + if (locale.languageCode === 'ji') { + // yiddish + locale.languageCode = 'yi' + } + + // @ts-ignore checked above + output.push(locale) + } + } + + return output +} + +/** + * BCP-47 language tag without region e.g. array of 2-char lang codes + * + * {@link https://docs.expo.dev/versions/latest/sdk/localization/#locale} + */ +export const deviceLanguageCodes = dedupArray( + getLocales().map(l => l.languageCode), +) diff --git a/src/locale/helpers.ts b/src/locale/helpers.ts index 3bae45214d..507e1f98b7 100644 --- a/src/locale/helpers.ts +++ b/src/locale/helpers.ts @@ -160,8 +160,13 @@ export function sanitizeAppLanguageSetting(appLanguage: string): AppLanguage { return AppLanguage.en } +/** + * Handles legacy migration for Java devices. + * + * {@link https://github.com/bluesky-social/social-app/pull/4461} + * {@link https://xml.coverpages.org/iso639a.html} + */ export function fixLegacyLanguageCode(code: string | null): string | null { - // handle some legacy code conversions, see https://xml.coverpages.org/iso639a.html if (code === 'in') { // indonesian return 'id' diff --git a/src/platform/detection.ts b/src/platform/detection.ts index c62ae71aae..dc30c2fd33 100644 --- a/src/platform/detection.ts +++ b/src/platform/detection.ts @@ -1,8 +1,4 @@ import {Platform} from 'react-native' -import {getLocales} from 'expo-localization' - -import {fixLegacyLanguageCode} from '#/locale/helpers' -import {dedupArray} from 'lib/functions' export const isIOS = Platform.OS === 'ios' export const isAndroid = Platform.OS === 'android' @@ -15,9 +11,3 @@ export const isMobileWeb = // @ts-ignore we know window exists -prf global.window.matchMedia(isMobileWebMediaQuery)?.matches export const isIPhoneWeb = isWeb && /iPhone/.test(navigator.userAgent) - -export const deviceLocales = dedupArray( - getLocales?.() - .map?.(locale => fixLegacyLanguageCode(locale.languageCode)) - .filter(code => typeof code === 'string'), -) as string[] diff --git a/src/state/persisted/schema.ts b/src/state/persisted/schema.ts index 2a3e49bfc1..8189f72b86 100644 --- a/src/state/persisted/schema.ts +++ b/src/state/persisted/schema.ts @@ -1,7 +1,7 @@ import {z} from 'zod' +import {deviceLanguageCodes} from '#/locale/deviceLocales' import {logger} from '#/logger' -import {deviceLocales} from '#/platform/detection' import {PlatformInfo} from '../../../modules/expo-bluesky-swiss-army' const externalEmbedOptions = ['show', 'hide'] as const @@ -125,13 +125,13 @@ export const defaults: Schema = { lastEmailConfirm: undefined, }, languagePrefs: { - primaryLanguage: deviceLocales[0] || 'en', - contentLanguages: deviceLocales || [], - postLanguage: deviceLocales[0] || 'en', - postLanguageHistory: (deviceLocales || []) + primaryLanguage: deviceLanguageCodes[0] || 'en', + contentLanguages: deviceLanguageCodes || [], + postLanguage: deviceLanguageCodes[0] || 'en', + postLanguageHistory: (deviceLanguageCodes || []) .concat(['en', 'ja', 'pt', 'de']) .slice(0, 6), - appLanguage: deviceLocales[0] || 'en', + appLanguage: deviceLanguageCodes[0] || 'en', }, requireAltTextEnabled: false, largeAltBadgeEnabled: false, diff --git a/src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx b/src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx index b8c125b65c..017b59db9e 100644 --- a/src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx +++ b/src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx @@ -1,19 +1,20 @@ import React from 'react' import {StyleSheet, View} from 'react-native' -import {ScrollView} from '../util' -import {Text} from '../../util/text/Text' -import {usePalette} from 'lib/hooks/usePalette' -import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' -import {deviceLocales} from 'platform/detection' -import {LANGUAGES, LANGUAGES_MAP_CODE2} from '../../../../locale/languages' -import {LanguageToggle} from './LanguageToggle' -import {ConfirmLanguagesButton} from './ConfirmLanguagesButton' import {Trans} from '@lingui/macro' + +import {deviceLanguageCodes} from '#/locale/deviceLocales' import {useModalControls} from '#/state/modals' import { useLanguagePrefs, useLanguagePrefsApi, } from '#/state/preferences/languages' +import {usePalette} from 'lib/hooks/usePalette' +import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' +import {LANGUAGES, LANGUAGES_MAP_CODE2} from '../../../../locale/languages' +import {Text} from '../../util/text/Text' +import {ScrollView} from '../util' +import {ConfirmLanguagesButton} from './ConfirmLanguagesButton' +import {LanguageToggle} from './LanguageToggle' export const snapPoints = ['100%'] @@ -37,10 +38,10 @@ export function Component({}: {}) { langs.sort((a, b) => { const hasA = langPrefs.contentLanguages.includes(a.code2) || - deviceLocales.includes(a.code2) + deviceLanguageCodes.includes(a.code2) const hasB = langPrefs.contentLanguages.includes(b.code2) || - deviceLocales.includes(b.code2) + deviceLanguageCodes.includes(b.code2) if (hasA === hasB) return a.name.localeCompare(b.name) if (hasA) return -1 return 1 diff --git a/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx b/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx index 05cfb81156..a20458702e 100644 --- a/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx +++ b/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx @@ -1,20 +1,21 @@ import React from 'react' import {StyleSheet, View} from 'react-native' -import {ScrollView} from '../util' -import {Text} from '../../util/text/Text' -import {usePalette} from 'lib/hooks/usePalette' -import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' -import {deviceLocales} from 'platform/detection' -import {LANGUAGES, LANGUAGES_MAP_CODE2} from '../../../../locale/languages' -import {ConfirmLanguagesButton} from './ConfirmLanguagesButton' -import {ToggleButton} from 'view/com/util/forms/ToggleButton' import {Trans} from '@lingui/macro' + +import {deviceLanguageCodes} from '#/locale/deviceLocales' import {useModalControls} from '#/state/modals' import { + hasPostLanguage, useLanguagePrefs, useLanguagePrefsApi, - hasPostLanguage, } from '#/state/preferences/languages' +import {usePalette} from 'lib/hooks/usePalette' +import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' +import {ToggleButton} from 'view/com/util/forms/ToggleButton' +import {LANGUAGES, LANGUAGES_MAP_CODE2} from '../../../../locale/languages' +import {Text} from '../../util/text/Text' +import {ScrollView} from '../util' +import {ConfirmLanguagesButton} from './ConfirmLanguagesButton' export const snapPoints = ['100%'] @@ -38,10 +39,10 @@ export function Component() { langs.sort((a, b) => { const hasA = hasPostLanguage(langPrefs.postLanguage, a.code2) || - deviceLocales.includes(a.code2) + deviceLanguageCodes.includes(a.code2) const hasB = hasPostLanguage(langPrefs.postLanguage, b.code2) || - deviceLocales.includes(b.code2) + deviceLanguageCodes.includes(b.code2) if (hasA === hasB) return a.name.localeCompare(b.name) if (hasA) return -1 return 1