-
-
Notifications
You must be signed in to change notification settings - Fork 764
/
serverSideTranslations.ts
136 lines (112 loc) · 3.51 KB
/
serverSideTranslations.ts
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import fs from 'fs'
import path from 'path'
import { createConfig } from './config/createConfig'
import createClient from './createClient/node'
import { globalI18n } from './appWithTranslation'
import { UserConfig, SSRConfig } from './types'
import { getFallbackForLng, unique } from './utils'
import { Module, Namespace } from 'i18next'
let DEFAULT_CONFIG_PATH = './next-i18next.config.js'
/**
* One line expression like `const { I18NEXT_DEFAULT_CONFIG_PATH: DEFAULT_CONFIG_PATH = './next-i18next.config.js' } = process.env;`
* is breaking the build, so keep it like this.
*
* @see https://github.com/i18next/next-i18next/pull/2084#issuecomment-1420511358
*/
if (process.env.I18NEXT_DEFAULT_CONFIG_PATH) {
DEFAULT_CONFIG_PATH = process.env.I18NEXT_DEFAULT_CONFIG_PATH
}
type ArrayElementOrSelf<T> = T extends ReadonlyArray<infer U> ? U[] : T[]
export const serverSideTranslations = async (
initialLocale: string,
namespacesRequired:
| ArrayElementOrSelf<Namespace>
| string
| string[]
| undefined = undefined,
configOverride: UserConfig | null = null,
extraLocales: string[] | false = false
): Promise<SSRConfig> => {
if (typeof initialLocale !== 'string') {
throw new Error(
'Initial locale argument was not passed into serverSideTranslations'
)
}
let userConfig = configOverride
const configPath = path.resolve(DEFAULT_CONFIG_PATH)
if (!userConfig && fs.existsSync(configPath)) {
userConfig = await import(configPath)
}
if (userConfig === null) {
throw new Error(
`next-i18next was unable to find a user config at ${configPath}`
)
}
const config = createConfig({
...userConfig,
lng: initialLocale,
})
const {
localeExtension,
localePath,
fallbackLng,
reloadOnPrerender,
} = config
if (reloadOnPrerender) {
await globalI18n?.reloadResources()
}
const { i18n, initPromise } = createClient({
...config,
lng: initialLocale,
})
await initPromise
const hasCustomBackend = userConfig?.use?.some(
(b: Module) => b.type === 'backend'
)
if (hasCustomBackend && namespacesRequired) {
await i18n.loadNamespaces(Array.isArray(namespacesRequired) ? (namespacesRequired as string[]) : (namespacesRequired as string))
}
const initialI18nStore: Record<string, any> = {
[initialLocale]: {},
}
getFallbackForLng(initialLocale, fallbackLng ?? false)
.concat(extraLocales || [])
.forEach((lng: string) => {
initialI18nStore[lng] = {}
})
if (!Array.isArray(namespacesRequired)) {
if (typeof localePath === 'function') {
throw new Error(
'Must provide namespacesRequired to serverSideTranslations when using a function as localePath'
)
}
const getLocaleNamespaces = (path: string) =>
fs.existsSync(path)
? fs
.readdirSync(path)
.map(file => file.replace(`.${localeExtension}`, ''))
: []
const namespacesByLocale = Object.keys(initialI18nStore)
.map(locale =>
getLocaleNamespaces(
path.resolve(process.cwd(), `${localePath}/${locale}`)
)
)
.flat()
namespacesRequired = unique(namespacesByLocale)
}
namespacesRequired.forEach(ns => {
for (const locale in initialI18nStore) {
initialI18nStore[locale][ns] =
(i18n.services.resourceStore.data[locale] || {})[ns] || {}
}
})
return {
_nextI18Next: {
initialI18nStore,
initialLocale,
ns: namespacesRequired,
userConfig: config.serializeConfig ? userConfig : null,
},
}
}