Cleanup - unused files / unused exports / duplicate exports
[ProtonMail-WebClient.git] / packages / shared / lib / i18n / helper.ts
blobc6268003bba433ff11f9c1f093aae78f1d4dff5a
1 import { DEFAULT_LOCALE } from '../constants';
3 export const getNormalizedLocale = (locale = '') => {
4     return locale.toLowerCase().replace(/-/g, '_');
5 };
7 // Attempts to convert the original locale (en_US) to BCP 47 (en-US) as supported by the lang attribute
8 export const getLangAttribute = (locale: string) => {
9     return locale.replace(/_/g, '-').replace('es-LA', 'es');
12 /**
13  * Takes the first portion, e.g. nl_NL => nl, kab_KAB => kab
14  */
15 export const getLanguageCode = (locale = '') => {
16     return getNormalizedLocale(locale).split('_')[0];
19 /**
20  * Takes the second portion, e.g. nl_NL => nl, fr_CA => ca
21  * ** Only for the locale user setting you are guaranteed to get an ISO_3166-1_alpha-2 country code. You may get undefined for other locale instances **
22  */
23 export const getNaiveCountryCode = (locale = '') => {
24     return getNormalizedLocale(locale).split('_')[1];
27 /**
28  * Transforms a locale string into one that can be passed to Javascript Intl methods.
29  * Basically transforms zh_ZH => zh-ZH, es-es => es-es (Intl cares about the dash, but not about capitalization)
30  */
31 export const getIntlLocale = (locale = '') => {
32     return getNormalizedLocale(locale).replace(/_/g, '-');
35 export const getBrowserLanguageTags = (): string[] => {
36     const tags = window.navigator?.languages;
37     return [...tags];
40 /**
41  * Gets the first specified locale from the browser, if any.
42  *
43  * If the first locale does not have a region and the second is a regional variant of the first, take it instead.
44  */
45 export const getBrowserLocale = () => {
46     const first = window.navigator?.languages?.[0];
47     const second = window.navigator?.languages?.[1];
49     if (!/[_-]/.test(first) && /[_-]/.test(second) && getLanguageCode(first) === getLanguageCode(second)) {
50         return second;
51     }
53     return first;
56 /**
57  * Give a higher score to locales with higher chances to be a proper fallback languages
58  * when there is no exact match.
59  */
60 const getLanguagePriority = (locale: string) => {
61     const parts = locale.toLowerCase().split(/[_-]/);
63     // Prefer language (en) over language + region (en_US)
64     if (parts.length === 1) {
65         return 2;
66     }
68     // Prefer region matching language (fr_FR, it_IT, de_DE) over other regions (fr_CA, it_CH, de_AU)
69     return parts[0] === parts[1] ? 1 : 0;
72 /**
73  * Get the closest matching locale from an object of locales.
74  */
75 export const getClosestLocaleMatch = (locale = '', locales = {}) => {
76     const localeKeys = [DEFAULT_LOCALE, ...Object.keys(locales)].sort((first, second) => {
77         if (first === second) {
78             return 0;
79         }
81         const firstPriority = getLanguagePriority(first);
82         const secondPriority = getLanguagePriority(second);
84         if (firstPriority > secondPriority) {
85             return -1;
86         }
88         if (firstPriority < secondPriority) {
89             return 1;
90         }
92         return first > second ? 1 : -1;
93     });
94     const normalizedLocaleKeys = localeKeys.map(getNormalizedLocale);
95     const normalizedLocale = getNormalizedLocale(locale);
97     // First by language and country code.
98     const fullMatchIndex = normalizedLocaleKeys.findIndex((key) => key === normalizedLocale);
99     if (fullMatchIndex >= 0) {
100         return localeKeys[fullMatchIndex];
101     }
103     // Language code.
104     const language = getLanguageCode(normalizedLocale);
105     const languageMatchIndex = normalizedLocaleKeys.findIndex((key) => {
106         return getLanguageCode(key) === language;
107     });
108     if (languageMatchIndex >= 0) {
109         return localeKeys[languageMatchIndex];
110     }
113 export const getClosestLocaleCode = (locale: string | undefined, locales: { [key: string]: any }) => {
114     if (!locale) {
115         return DEFAULT_LOCALE;
116     }
117     return getClosestLocaleMatch(locale, locales) || DEFAULT_LOCALE;