1/* eslint-env browser */ 2import { Platform } from 'expo-modules-core'; 3import * as rtlDetect from 'rtl-detect'; 4const getNavigatorLocales = () => { 5 return Platform.isDOMAvailable ? navigator.languages || [navigator.language] : []; 6}; 7const WEB_LANGUAGE_CHANGE_EVENT = 'languagechange'; 8// https://wisevoter.com/country-rankings/countries-that-use-fahrenheit/ 9const USES_FAHRENHEIT = [ 10 'AG', 11 'BZ', 12 'VG', 13 'FM', 14 'MH', 15 'MS', 16 'KN', 17 'BS', 18 'CY', 19 'TC', 20 'US', 21 'LR', 22 'PW', 23 'KY', 24]; 25export function addLocaleListener(listener) { 26 addEventListener(WEB_LANGUAGE_CHANGE_EVENT, listener); 27 return { 28 remove: () => removeEventListener(WEB_LANGUAGE_CHANGE_EVENT, listener), 29 }; 30} 31export function addCalendarListener(listener) { 32 addEventListener(WEB_LANGUAGE_CHANGE_EVENT, listener); 33 return { 34 remove: () => removeEventListener(WEB_LANGUAGE_CHANGE_EVENT, listener), 35 }; 36} 37export function removeSubscription(subscription) { 38 subscription.remove(); 39} 40export default { 41 get currency() { 42 // TODO: Add support 43 return null; 44 }, 45 get decimalSeparator() { 46 return (1.1).toLocaleString().substring(1, 2); 47 }, 48 get digitGroupingSeparator() { 49 const value = (1000).toLocaleString(); 50 return value.length === 5 ? value.substring(1, 2) : ''; 51 }, 52 get isRTL() { 53 return rtlDetect.isRtlLang(this.locale) ?? false; 54 }, 55 get isMetric() { 56 const { region } = this; 57 switch (region) { 58 case 'US': // USA 59 case 'LR': // Liberia 60 case 'MM': // Myanmar 61 return false; 62 } 63 return true; 64 }, 65 get locale() { 66 if (!Platform.isDOMAvailable) { 67 return ''; 68 } 69 const locale = navigator.language || 70 navigator['systemLanguage'] || 71 navigator['browserLanguage'] || 72 navigator['userLanguage'] || 73 this.locales[0]; 74 return locale; 75 }, 76 get locales() { 77 if (!Platform.isDOMAvailable) { 78 return []; 79 } 80 const { languages = [] } = navigator; 81 return Array.from(languages); 82 }, 83 get timezone() { 84 const defaultTimeZone = 'Etc/UTC'; 85 if (typeof Intl === 'undefined') { 86 return defaultTimeZone; 87 } 88 return Intl.DateTimeFormat().resolvedOptions().timeZone || defaultTimeZone; 89 }, 90 get isoCurrencyCodes() { 91 // TODO(Bacon): Add this - very low priority 92 return []; 93 }, 94 get region() { 95 // There is no way to obtain the current region, as is possible on native. 96 // Instead, use the country-code from the locale when possible (e.g. "en-US"). 97 const { locale } = this; 98 const [, ...suffixes] = typeof locale === 'string' ? locale.split('-') : []; 99 for (const suffix of suffixes) { 100 if (suffix.length === 2) { 101 return suffix.toUpperCase(); 102 } 103 } 104 return null; 105 }, 106 getLocales() { 107 const locales = getNavigatorLocales(); 108 return locales?.map((languageTag) => { 109 // TextInfo is an experimental API that is not available in all browsers. 110 // We might want to consider using a locale lookup table instead. 111 const locale = typeof Intl !== 'undefined' 112 ? new Intl.Locale(languageTag) 113 : { region: null, textInfo: null, language: null }; 114 const { region, textInfo, language } = locale; 115 // Properties added only for compatibility with native, use `toLocaleString` instead. 116 const digitGroupingSeparator = Array.from((10000).toLocaleString(languageTag)).filter((c) => c > '9' || c < '0')[0] || 117 null; // using 1e5 instead of 1e4 since for some locales (like pl-PL) 1e4 does not use digit grouping 118 const decimalSeparator = (1.1).toLocaleString(languageTag).substring(1, 2); 119 const temperatureUnit = region ? regionToTemperatureUnit(region) : null; 120 return { 121 languageTag, 122 languageCode: language || languageTag.split('-')[0] || 'en', 123 textDirection: textInfo?.direction || null, 124 digitGroupingSeparator, 125 decimalSeparator, 126 measurementSystem: null, 127 currencyCode: null, 128 currencySymbol: null, 129 regionCode: region || null, 130 temperatureUnit, 131 }; 132 }); 133 }, 134 getCalendars() { 135 const locale = ((typeof Intl !== 'undefined' 136 ? Intl.DateTimeFormat().resolvedOptions() 137 : null) ?? null); 138 return [ 139 { 140 calendar: (locale?.calendar || locale?.calendars?.[0]) || null, 141 timeZone: locale?.timeZone || locale?.timeZones?.[0] || null, 142 uses24hourClock: (locale?.hourCycle || locale?.hourCycles?.[0])?.startsWith('h2') ?? null, 143 firstWeekday: locale?.weekInfo?.firstDay || null, 144 }, 145 ]; 146 }, 147 async getLocalizationAsync() { 148 const { currency, decimalSeparator, digitGroupingSeparator, isoCurrencyCodes, isMetric, isRTL, locale, locales, region, timezone, } = this; 149 return { 150 currency, 151 decimalSeparator, 152 digitGroupingSeparator, 153 isoCurrencyCodes, 154 isMetric, 155 isRTL, 156 locale, 157 locales, 158 region, 159 timezone, 160 }; 161 }, 162}; 163function regionToTemperatureUnit(region) { 164 return USES_FAHRENHEIT.includes(region) ? 'fahrenheit' : 'celsius'; 165} 166//# sourceMappingURL=ExpoLocalization.js.map