1import { useEffect, useReducer, useMemo } from 'react';
2
3import ExpoLocalization, {
4  addCalendarListener,
5  addLocaleListener,
6  removeSubscription,
7} from './ExpoLocalization';
8import { Localization } from './Localization.types';
9export * from './Localization.types';
10
11// @needsAudit
12/**
13 * @deprecated Use Localization.getLocales() instead.
14 * Three-character ISO 4217 currency code. Returns `null` on web.
15 *
16 * @example `'USD'`, `'EUR'`, `'CNY'`, `null`
17 */
18export const currency = ExpoLocalization.currency;
19
20// @needsAudit
21/**
22 * @deprecated Use Localization.getLocales() instead.
23 * Decimal separator used for formatting numbers.
24 *
25 * @example `','`, `'.'`
26 */
27export const decimalSeparator = ExpoLocalization.decimalSeparator;
28
29// @needsAudit
30/**
31 * @deprecated Use Localization.getLocales() instead.
32 * Digit grouping separator used when formatting numbers larger than 1000.
33 *
34 * @example `'.'`, `''`, `','`
35 */
36export const digitGroupingSeparator = ExpoLocalization.digitGroupingSeparator;
37
38// @needsAudit
39/**
40 * @deprecated Use Localization.getLocales() instead.
41 * A list of all the supported language ISO codes.
42 */
43export const isoCurrencyCodes = ExpoLocalization.isoCurrencyCodes;
44
45// @needsAudit
46/**
47 * @deprecated Use Localization.getLocales() instead.
48 * Boolean value that indicates whether the system uses the metric system.
49 * On Android and web, this is inferred from the current region.
50 */
51export const isMetric = ExpoLocalization.isMetric;
52
53// @needsAudit
54/**
55 * @deprecated Use Localization.getLocales() instead.
56 * Returns if the system's language is written from Right-to-Left.
57 * This can be used to build features like [bidirectional icons](https://material.io/design/usability/bidirectionality.html).
58 *
59 * Returns `false` in Server Side Rendering (SSR) environments.
60 */
61export const isRTL = ExpoLocalization.isRTL;
62
63// @needsAudit
64/**
65 * Consider using Localization.getLocales() for a list of user preferred locales instead.
66 * An [IETF BCP 47 language tag](https://en.wikipedia.org/wiki/IETF_language_tag),
67 * consisting of a two-character language code and optional script, region and variant codes.
68 *
69 * @example `'en'`, `'en-US'`, `'zh-Hans'`, `'zh-Hans-CN'`, `'en-emodeng'`
70 */
71export const locale = ExpoLocalization.locale;
72
73// @needsAudit
74/**
75 * @deprecated Use Localization.getLocales() instead.
76 * List of all the native languages provided by the user settings.
77 * These are returned in the order the user defines in their device settings.
78 *
79 * @example `['en', 'en-US', 'zh-Hans', 'zh-Hans-CN', 'en-emodeng']`
80 */
81export const locales = ExpoLocalization.locales;
82
83// @needsAudit
84/**
85 * @deprecated Use Localization.getCalendars() instead.
86 * The current time zone in display format.
87 * On Web time zone is calculated with Intl.DateTimeFormat().resolvedOptions().timeZone. For a
88 * better estimation you could use the moment-timezone package but it will add significant bloat to
89 * your website's bundle size.
90 *
91 * @example `'America/Los_Angeles'`
92 */
93export const timezone = ExpoLocalization.timezone;
94
95// @needsAudit
96/**
97 * @deprecated Use Localization.getLocales() instead.
98 * The region code for your device that comes from the Region setting under Language & Region on iOS.
99 * This value is always available on iOS, but might return `null` on Android or web.
100 *
101 * @example `'US'`, `'NZ'`, `null`
102 */
103export const region = ExpoLocalization.region;
104
105/**
106 * List of user's locales, returned as an array of objects of type `Locale`.
107 * Guaranteed to contain at least 1 element.
108 * These are returned in the order the user defines in their device settings.
109 * On the web currency and measurements systems are not provided, instead returned as null.
110 * If needed, you can infer them from the current region using a lookup table.
111 * @example `[{
112    "languageTag": "pl-PL",
113    "languageCode": "pl",
114    "textDirection": "ltr",
115    "digitGroupingSeparator": " ",
116    "decimalSeparator": ",",
117    "measurementSystem": "metric",
118    "currencyCode": "PLN",
119    "currencySymbol": "zł",
120    "regionCode": "PL",
121    "temperatureUnit": "celsius"
122  }]`
123 */
124export const getLocales = ExpoLocalization.getLocales;
125
126/**
127 * List of user's preferred calendars, returned as an array of objects of type `Calendar`.
128 * Guaranteed to contain at least 1 element.
129 * For now always returns a single element, but it's likely to return a user preference list on some platforms in the future.
130 * @example `[
131    {
132      "calendar": "gregory",
133      "timeZone": "Europe/Warsaw",
134      "uses24hourClock": true,
135      "firstWeekday": 1
136    }
137  ]`
138 */
139export const getCalendars = ExpoLocalization.getCalendars;
140
141/**
142 * A hook providing a list of user's locales, returned as an array of objects of type `Locale`.
143 * Guaranteed to contain at least 1 element.
144 * These are returned in the order the user defines in their device settings.
145 * On the web currency and measurements systems are not provided, instead returned as null.
146 * If needed, you can infer them from the current region using a lookup table.
147 * If the OS settings change, the hook will rerender with a new list of locales.
148 * @example `[{
149    "languageTag": "pl-PL",
150    "languageCode": "pl",
151    "textDirection": "ltr",
152    "digitGroupingSeparator": " ",
153    "decimalSeparator": ",",
154    "measurementSystem": "metric",
155    "currencyCode": "PLN",
156    "currencySymbol": "zł",
157    "regionCode": "PL",
158    "temperatureUnit": "celsius"
159  }]`
160 */
161export function useLocales() {
162  const [key, invalidate] = useReducer((k) => k + 1, 0);
163  const locales = useMemo(() => getLocales(), [key]);
164  useEffect(() => {
165    const subscription = addLocaleListener(invalidate);
166    return () => {
167      removeSubscription(subscription);
168    };
169  }, []);
170  return locales;
171}
172
173/**
174 * A hook providing a list of user's preferred calendars, returned as an array of objects of type `Calendar`.
175 * Guaranteed to contain at least 1 element.
176 * For now always returns a single element, but it's likely to return a user preference list on some platforms in the future.
177 * If the OS settings change, the hook will rerender with a new list of calendars.
178 * @example `[
179    {
180      "calendar": "gregory",
181      "timeZone": "Europe/Warsaw",
182      "uses24hourClock": true,
183      "firstWeekday": 1
184    }
185  ]`
186 */
187export function useCalendars() {
188  const [key, invalidate] = useReducer((k) => k + 1, 0);
189  const calendars = useMemo(() => getCalendars(), [key]);
190  useEffect(() => {
191    const subscription = addCalendarListener(invalidate);
192    return () => {
193      removeSubscription(subscription);
194    };
195  }, []);
196  return calendars;
197}
198
199// @needsAudit
200/**
201 * Get the latest native values from the device. Locale can be changed on some Android devices
202 * without resetting the app.
203 * > On iOS, changing the locale will cause the device to reset meaning the constants will always be
204 * correct.
205 *
206 * @example
207 * ```ts
208 * // When the app returns from the background on Android...
209 *
210 * const { locale } = await Localization.getLocalizationAsync();
211 * ```
212 * @deprecated
213 * Use Localization.getLocales() or Localization.getCalendars() instead.
214 */
215export async function getLocalizationAsync(): Promise<Localization> {
216  return await ExpoLocalization.getLocalizationAsync();
217}
218