1import * as Localization from 'expo-localization'; 2import i18n from 'i18n-js'; 3import { Platform } from 'react-native'; 4 5const en = { 6 good: 'good', 7 morning: 'morning', 8}; 9 10const fr = { 11 good: 'bien', 12 morning: 'matin', 13}; 14 15const pl = { 16 good: 'dobry', 17 morning: 'rano', 18}; 19 20export const name = 'Localization'; 21 22export function test(t) { 23 function validateString(result) { 24 t.expect(result).toBeDefined(); 25 t.expect(typeof result).toBe('string'); 26 t.expect(result.length > 0).toBe(true); 27 } 28 29 function validateStringArray(result) { 30 t.expect(result).toBeDefined(); 31 t.expect(Array.isArray(result)).toBe(true); 32 } 33 34 t.describe(`Localization methods`, () => { 35 t.it('expect to getLocales return preferred locales', () => { 36 const locales = Localization.getLocales(); 37 t.expect(locales.length).toBeGreaterThanOrEqual(1); 38 const { 39 languageTag, 40 languageCode, 41 regionCode, 42 currencyCode, 43 currencySymbol, 44 decimalSeparator, 45 digitGroupingSeparator, 46 textDirection, 47 measurementSystem, 48 } = locales[0]; 49 validateString(languageTag); 50 validateString(languageCode); 51 // following properties can be nullish if the locale does not provide/override them 52 t.expect(regionCode).toBeDefined(); 53 t.expect(currencyCode).toBeDefined(); 54 t.expect(currencySymbol).toBeDefined(); 55 t.expect(decimalSeparator).toBeDefined(); 56 t.expect(digitGroupingSeparator).toBeDefined(); 57 t.expect(textDirection).toBeDefined(); 58 if (textDirection) { 59 t.expect(['rtl', 'ltr'].includes(textDirection)).toBe(true); 60 } 61 t.expect(measurementSystem).toBeDefined(); 62 if (measurementSystem) { 63 t.expect(['metric', 'us', 'uk'].includes(measurementSystem)).toBe(true); 64 } 65 }); 66 67 t.it('expect getCalendars to return at least a single calendar', () => { 68 const calendars = Localization.getCalendars(); 69 t.expect(calendars.length).toBeGreaterThanOrEqual(1); 70 const { calendar, uses24hourClock, firstWeekday, timeZone } = calendars[0]; 71 t.expect(calendar).toBeDefined(); 72 t.expect(timeZone).toBeDefined(); 73 // following properties can be nullish if the locale does not provide/override them 74 t.expect(uses24hourClock).toBeDefined(); 75 if (uses24hourClock !== null) { 76 t.expect(typeof uses24hourClock).toBe('boolean'); 77 } 78 t.expect(firstWeekday).toBeDefined(); 79 if (firstWeekday !== null) { 80 t.expect(typeof firstWeekday).toBe('number'); 81 } 82 }); 83 84 t.it('expect async to return locale', async () => { 85 const { 86 currency, 87 decimalSeparator, 88 digitGroupingSeparator, 89 isoCurrencyCodes, 90 isMetric, 91 isRTL, 92 locale, 93 locales, 94 timezone, 95 region, 96 } = await Localization.getLocalizationAsync(); 97 98 validateString(locale); 99 validateString(timezone); 100 if (Platform.OS !== 'web' || region) { 101 validateString(region); 102 } 103 validateStringArray(isoCurrencyCodes); 104 validateStringArray(locales); 105 t.expect(locales[0]).toBe(Localization.locale); 106 t.expect(typeof isRTL).toBe('boolean'); 107 t.expect(typeof isMetric).toBe('boolean'); 108 validateString(decimalSeparator); 109 validateString(digitGroupingSeparator); 110 if (Platform.OS !== 'web' || currency) { 111 validateString(currency); 112 } 113 }); 114 }); 115 116 t.describe(`Localization defines constants`, () => { 117 t.it('Gets the region', async () => { 118 const result = Localization.region; 119 if (Platform.OS !== 'web' || result) { 120 validateString(result); 121 } 122 }); 123 t.it('Gets the locale', async () => { 124 validateString(Localization.locale); 125 }); 126 t.it('Gets the preferred locales', async () => { 127 const result = Localization.locales; 128 validateStringArray(result); 129 t.expect(result.length > 0).toBe(true); 130 t.expect(result[0]).toBe(Localization.locale); 131 }); 132 t.it('Gets ISO currency codes', async () => { 133 const result = Localization.isoCurrencyCodes; 134 validateStringArray(result); 135 result.map(validateString); 136 }); 137 t.it('Gets the timezone', async () => { 138 const result = Localization.timezone; 139 if (result || Platform.OS !== 'web') { 140 validateString(Localization.timezone); 141 } 142 }); 143 t.it('Gets the layout direction (ltr only)', async () => { 144 const result = Localization.isRTL; 145 t.expect(typeof result).toBe('boolean'); 146 t.expect(result).toBe(false); 147 }); 148 t.it('Gets the measurement system (metric)', async () => { 149 const result = Localization.isMetric; 150 t.expect(typeof result).toBe('boolean'); 151 }); 152 t.it('Gets the decimal separator', async () => { 153 validateString(Localization.decimalSeparator); 154 }); 155 t.it('Gets the grouping separator', async () => { 156 const result = Localization.decimalSeparator; 157 t.expect(result).toBeDefined(); 158 t.expect(typeof result).toBe('string'); 159 }); 160 if (Platform.OS !== 'web') { 161 t.it('Gets the currency', async () => { 162 validateString(Localization.currency); 163 }); 164 } 165 }); 166 167 t.describe(`Localization works with i18n-js`, () => { 168 i18n.locale = Localization.locale; 169 i18n.translations = { en, fr, pl }; 170 i18n.missingTranslationPrefix = 'EE: '; 171 i18n.fallbacks = true; 172 173 t.it('expect language to match strings (en, pl, fr supported)', async () => { 174 const target = 'good'; 175 176 i18n.locale = Localization.locale; 177 178 const expoPredictedLangTag = Localization.locale.split('-')[0]; 179 const translation = i18n.translations[expoPredictedLangTag]; 180 181 t.expect(translation[target]).toBe(i18n.t(target)); 182 }); 183 }); 184} 185