-
-
Notifications
You must be signed in to change notification settings - Fork 521
Expand file tree
/
Copy pathi18n.jsx
More file actions
117 lines (100 loc) Β· 3.03 KB
/
i18n.jsx
File metadata and controls
117 lines (100 loc) Β· 3.03 KB
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import { createContext } from 'preact';
import { useContext, useEffect, useState } from 'preact/hooks';
import { useLocation } from 'preact-iso';
import { localStorageGet, localStorageSet } from './localstorage';
import config from '../config.json';
/**
* @typedef LanguageContext
* @property {string} lang
* @property {(string) => void} setLang
*/
/**
* @type {import('preact').Context<LanguageContext>}
*/
const LanguageContext = createContext(/** @type {LanguageContext} */ ({}));
/**
* Get the default language based on the preferred preference of the browser
* @param {Record<string, string>} available All available languages
* @returns {string | undefined}
*/
function getNavigatorLanguage(available) {
if (typeof navigator === 'undefined') return;
let langs = [navigator.language].concat(navigator.languages);
for (let i = 0; i < langs.length; i++) {
if (langs[i]) {
let lang = String(langs[i]).toLowerCase();
if (available[lang]) return lang;
// Respect order of `navigator.languages` by returning if the fallback language `English` is found
if (lang === 'en') return;
}
}
}
export function LanguageProvider({ children }) {
const { query } = useLocation();
// We only prerender in English
const [lang, setLang] = useState('en');
useEffect(() => {
const localStorageLang = localStorageGet('lang');
const navigatorLang = getNavigatorLanguage(config.languages);
const userLang = query.lang || localStorageLang || navigatorLang || 'en';
setLang(userLang);
document.documentElement.lang = userLang;
}, []);
const setAndUpdateHtmlAttr = lang => {
localStorageSet('lang', lang);
setLang(lang);
document.documentElement.lang = lang;
};
return (
<LanguageContext.Provider value={{ lang, setLang: setAndUpdateHtmlAttr }}>
{children}
</LanguageContext.Provider>
);
}
/**
* Handles all logic related to language settings
* @returns {[string, (v: string) => void]}
*/
export function useLanguage() {
const { lang, setLang } = useContext(LanguageContext);
return [lang, setLang];
}
/**
* Get the translation of a key. Defaults to English if no translation is found
* @param {keyof typeof config.i18n} key
* @returns {string}
*/
export function useTranslation(key) {
const [lang] = useLanguage();
const data = config.i18n[key];
return data[lang] || data.en;
}
/**
* Get the translated name of a path based upon the current language.
* @param {string} path
*/
export function useNavTranslation(path) {
const [lang] = useLanguage();
for (const route in config.nav) {
if (config.nav[route].path === path) {
return getRouteName(config.nav[route], lang);
} else if (config.nav[route].routes) {
for (const subRoute of config.nav[route].routes) {
if (subRoute.path === path) {
return getRouteName(subRoute, lang);
}
}
}
}
return null;
}
/**
* @param {{ name: Record<string, string> | string }} route
* @param {string} lang
* @return {string}
*/
export function getRouteName(route, lang) {
return typeof route.name === 'object'
? route.name[lang] || route.name.en
: route.name;
}