1 |
|
2 | import { Platform } from 'expo-modules-core';
|
3 | import * as rtlDetect from 'rtl-detect';
|
4 | const getNavigatorLocales = () => {
|
5 | return Platform.isDOMAvailable ? navigator.languages || [navigator.language] : [];
|
6 | };
|
7 | const WEB_LANGUAGE_CHANGE_EVENT = 'languagechange';
|
8 |
|
9 | const 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 | ];
|
25 | export function addLocaleListener(listener) {
|
26 | addEventListener(WEB_LANGUAGE_CHANGE_EVENT, listener);
|
27 | return {
|
28 | remove: () => removeEventListener(WEB_LANGUAGE_CHANGE_EVENT, listener),
|
29 | };
|
30 | }
|
31 | export function addCalendarListener(listener) {
|
32 | addEventListener(WEB_LANGUAGE_CHANGE_EVENT, listener);
|
33 | return {
|
34 | remove: () => removeEventListener(WEB_LANGUAGE_CHANGE_EVENT, listener),
|
35 | };
|
36 | }
|
37 | export function removeSubscription(subscription) {
|
38 | subscription.remove();
|
39 | }
|
40 | export default {
|
41 | get currency() {
|
42 |
|
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':
|
59 | case 'LR':
|
60 | case 'MM':
|
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 |
|
92 | return [];
|
93 | },
|
94 | get region() {
|
95 |
|
96 |
|
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 |
|
110 |
|
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 |
|
116 | const digitGroupingSeparator = Array.from((10000).toLocaleString(languageTag)).filter((c) => c > '9' || c < '0')[0] ||
|
117 | null;
|
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 | };
|
163 | function regionToTemperatureUnit(region) {
|
164 | return USES_FAHRENHEIT.includes(region) ? 'fahrenheit' : 'celsius';
|
165 | }
|
166 |
|
\ | No newline at end of file |