-
Notifications
You must be signed in to change notification settings - Fork 155
/
Copy pathIntlContext.tsx
98 lines (84 loc) · 2.73 KB
/
IntlContext.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import { type OnErrorFn } from '@formatjs/intl';
import { type Locale as DateFnsLocale } from 'date-fns';
import preferredLocale from 'preferred-locale';
import React, { useReducer } from 'react';
import { IntlProvider } from 'react-intl';
import { useAsync, useCookie, useEvent } from 'react-use';
import translations from 'app/locales';
type LocaleState = {
locale: string;
setLocale: (locale: string) => void;
unsetLocale: () => void;
};
function useLocaleState(locale?: string): LocaleState {
const [cookie, setCookie, unsetCookie] = useCookie('chosenLocale');
const availableLocales = Object.keys(translations);
const [, forceUpdate] = useReducer((x) => x + 1, 0);
// Listen for language change
useEvent('languagechange', forceUpdate, window);
if (locale) {
return { locale, setLocale: setCookie, unsetLocale: unsetCookie };
} else if (cookie) {
// If the user has chosen an invalid locale, delete it
if (cookie && availableLocales.indexOf(cookie) === -1) {
unsetCookie();
}
return { locale: cookie, setLocale: setCookie, unsetLocale: unsetCookie };
} else {
const availableLocales = Object.keys(translations);
return {
locale: preferredLocale(availableLocales, 'en'),
setLocale: setCookie,
unsetLocale: unsetCookie,
};
}
}
export const LocaleContext = React.createContext<{
locale: string;
setLocale: (locale: string) => void;
unsetLocale: () => void;
}>({
locale: 'en',
setLocale: () => null,
unsetLocale: () => null,
});
// @ts-ignore We guarantee that this is actually never null
export const DateFnsLocaleContext = React.createContext<DateFnsLocale>(null);
const IntlContext: React.FC<{ locale?: string }> = function ({
children,
locale,
}) {
const value = useLocaleState(locale);
const { value: localeData } = useAsync(
translations[value.locale].bundles.main,
);
const onError: OnErrorFn | undefined = import.meta.env.DEV
? (err) => {
if (err.code === 'MISSING_TRANSLATION') return;
throw err;
}
: undefined;
return localeData ? (
<LocaleContext.Provider value={value}>
<DateFnsLocaleContext.Provider value={localeData.dateFns}>
<IntlProvider
onError={onError}
locale={value.locale}
messages={localeData.kitsu}
key={value.locale}
defaultRichTextElements={{
b: (children) => <b>{children}</b>,
}}>
{children}
</IntlProvider>
</DateFnsLocaleContext.Provider>
</LocaleContext.Provider>
) : null;
};
export default IntlContext;
export function useLocale(): LocaleState {
return React.useContext(LocaleContext);
}
export function useDateFnsLocale(): DateFnsLocale {
return React.useContext(DateFnsLocaleContext);
}