-
-
Notifications
You must be signed in to change notification settings - Fork 206
/
I18nProvider.js
112 lines (94 loc) · 3.04 KB
/
I18nProvider.js
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
import React, { createContext, useContext } from 'react'
import I18nContext from './_context'
import { useRouter } from 'next/router'
const NsContext = createContext({})
/**
* Get value from key (allow nested keys as parent.children)
*/
function getDicValue(dic, key = '', options = { returnObjects: false }) {
const value = key.split('.').reduce((val, key) => val[key] || {}, dic)
if (
typeof value === 'string' ||
(value instanceof Object && options.returnObjects)
) {
return value
}
}
/**
* Control plural keys depending the {{count}} variable
*/
function plural(dic, key, query) {
if (!query || typeof query.count !== 'number') return key
const numKey = `${key}_${query.count}`
if (getDicValue(dic, numKey) !== undefined) return numKey
const pluralKey = `${key}_plural`
if (query.count > 1 && getDicValue(dic, pluralKey) !== undefined)
return pluralKey
return key
}
/**
* Replace {{variables}} to query values
*/
function interpolation(text, query) {
if (!text || !query) return text || ''
return Object.keys(query).reduce((all, varKey) => {
const regex = new RegExp(`{{\\s*${varKey}\\s*}}`, 'gm')
all = all.replace(regex, `${query[varKey]}`)
return all
}, text)
}
function objectInterpolation(obj, query) {
if (!query || Object.keys(query).length === 0) return obj
Object.keys(obj).forEach((key) => {
if (obj[key] instanceof Object) objectInterpolation(obj[key], query)
if (typeof obj[key] === 'string') obj[key] = interpolation(obj[key], query)
})
return obj
}
function missingKeyLogger({ namespace, i18nKey }) {
if (process.env.NODE_ENV === 'production') return
// This means that instead of "ns:value", "value" has been misspelled (without namespace)
if (!i18nKey) {
console.warn(
`[next-translate] The text "${namespace}" has no namespace in front of it.`
)
return
}
console.warn(
`[next-translate] "${namespace}:${i18nKey}" is missing in current namespace configuration. Try adding "${i18nKey}" to the namespace "${namespace}".`
)
}
export default function I18nProvider({
lang: lng,
namespaces = {},
children,
logger = missingKeyLogger,
}) {
const { locale } = useRouter() || {}
const lang = lng || locale
const ns = useContext(NsContext)
const allNamespaces = { ...ns, ...namespaces }
function t(key = '', query, options) {
const k = Array.isArray(key) ? key[0] : key
const [namespace, i18nKey] = k.split(/:(.+)/)
const dic = allNamespaces[namespace] || {}
const keyWithPlural = plural(dic, i18nKey, query)
const value = getDicValue(dic, keyWithPlural, options)
// Log only during CSR
if (typeof window !== 'undefined' && typeof value === 'undefined') {
logger({
namespace,
i18nKey,
})
}
if (value instanceof Object) {
return objectInterpolation(value, query)
}
return interpolation(value, query) || k
}
return (
<I18nContext.Provider value={{ lang, t }}>
<NsContext.Provider value={allNamespaces}>{children}</NsContext.Provider>
</I18nContext.Provider>
)
}