@modern-js/plugin-i18n 2.69.7 → 3.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/dist/cjs/cli/index.cjs +154 -0
- package/dist/cjs/runtime/I18nLink.cjs +68 -0
- package/dist/cjs/runtime/context.cjs +138 -0
- package/dist/cjs/runtime/hooks.cjs +189 -0
- package/dist/cjs/runtime/i18n/backend/config.cjs +39 -0
- package/dist/cjs/runtime/i18n/backend/defaults.cjs +56 -0
- package/dist/cjs/runtime/i18n/backend/defaults.node.cjs +56 -0
- package/dist/cjs/runtime/i18n/backend/index.cjs +108 -0
- package/dist/cjs/runtime/i18n/backend/middleware.cjs +54 -0
- package/dist/cjs/runtime/i18n/backend/middleware.common.cjs +105 -0
- package/dist/cjs/runtime/i18n/backend/middleware.node.cjs +58 -0
- package/dist/cjs/runtime/i18n/backend/sdk-backend.cjs +171 -0
- package/dist/cjs/runtime/i18n/detection/config.cjs +63 -0
- package/dist/cjs/runtime/i18n/detection/index.cjs +309 -0
- package/dist/cjs/runtime/i18n/detection/middleware.cjs +185 -0
- package/dist/cjs/runtime/i18n/detection/middleware.node.cjs +74 -0
- package/dist/cjs/runtime/i18n/index.cjs +43 -0
- package/dist/cjs/runtime/i18n/instance.cjs +132 -0
- package/dist/cjs/runtime/i18n/utils.cjs +185 -0
- package/dist/cjs/runtime/index.cjs +172 -0
- package/dist/cjs/runtime/types.cjs +18 -0
- package/dist/cjs/runtime/utils.cjs +134 -0
- package/dist/cjs/server/index.cjs +178 -0
- package/dist/cjs/shared/deepMerge.cjs +54 -0
- package/dist/cjs/shared/detection.cjs +105 -0
- package/dist/cjs/shared/type.cjs +18 -0
- package/dist/cjs/shared/utils.cjs +78 -0
- package/dist/esm/cli/index.js +106 -0
- package/dist/esm/runtime/I18nLink.js +31 -0
- package/dist/esm/runtime/context.js +101 -0
- package/dist/esm/runtime/hooks.js +146 -0
- package/dist/esm/runtime/i18n/backend/config.js +5 -0
- package/dist/esm/runtime/i18n/backend/defaults.js +19 -0
- package/dist/esm/runtime/i18n/backend/defaults.node.js +19 -0
- package/dist/esm/runtime/i18n/backend/index.js +74 -0
- package/dist/esm/runtime/i18n/backend/middleware.common.js +61 -0
- package/dist/esm/runtime/i18n/backend/middleware.js +7 -0
- package/dist/esm/runtime/i18n/backend/middleware.node.js +8 -0
- package/dist/esm/runtime/i18n/backend/sdk-backend.js +137 -0
- package/dist/esm/runtime/i18n/detection/config.js +26 -0
- package/dist/esm/runtime/i18n/detection/index.js +260 -0
- package/dist/esm/runtime/i18n/detection/middleware.js +132 -0
- package/dist/esm/runtime/i18n/detection/middleware.node.js +31 -0
- package/dist/esm/runtime/i18n/index.js +3 -0
- package/dist/esm/runtime/i18n/instance.js +77 -0
- package/dist/esm/runtime/i18n/utils.js +136 -0
- package/dist/esm/runtime/index.js +129 -0
- package/dist/esm/runtime/types.js +0 -0
- package/dist/esm/runtime/utils.js +82 -0
- package/dist/esm/server/index.js +168 -0
- package/dist/esm/shared/deepMerge.js +20 -0
- package/dist/esm/shared/detection.js +71 -0
- package/dist/esm/shared/type.js +0 -0
- package/dist/esm/shared/utils.js +35 -0
- package/dist/esm-node/cli/index.js +106 -0
- package/dist/esm-node/runtime/I18nLink.js +31 -0
- package/dist/esm-node/runtime/context.js +101 -0
- package/dist/esm-node/runtime/hooks.js +146 -0
- package/dist/esm-node/runtime/i18n/backend/config.js +5 -0
- package/dist/esm-node/runtime/i18n/backend/defaults.js +19 -0
- package/dist/esm-node/runtime/i18n/backend/defaults.node.js +19 -0
- package/dist/esm-node/runtime/i18n/backend/index.js +74 -0
- package/dist/esm-node/runtime/i18n/backend/middleware.common.js +61 -0
- package/dist/esm-node/runtime/i18n/backend/middleware.js +7 -0
- package/dist/esm-node/runtime/i18n/backend/middleware.node.js +8 -0
- package/dist/esm-node/runtime/i18n/backend/sdk-backend.js +137 -0
- package/dist/esm-node/runtime/i18n/detection/config.js +26 -0
- package/dist/esm-node/runtime/i18n/detection/index.js +260 -0
- package/dist/esm-node/runtime/i18n/detection/middleware.js +132 -0
- package/dist/esm-node/runtime/i18n/detection/middleware.node.js +31 -0
- package/dist/esm-node/runtime/i18n/index.js +3 -0
- package/dist/esm-node/runtime/i18n/instance.js +77 -0
- package/dist/esm-node/runtime/i18n/utils.js +136 -0
- package/dist/esm-node/runtime/index.js +129 -0
- package/dist/esm-node/runtime/types.js +0 -0
- package/dist/esm-node/runtime/utils.js +82 -0
- package/dist/esm-node/server/index.js +168 -0
- package/dist/esm-node/shared/deepMerge.js +20 -0
- package/dist/esm-node/shared/detection.js +71 -0
- package/dist/esm-node/shared/type.js +0 -0
- package/dist/esm-node/shared/utils.js +35 -0
- package/dist/types/cli/index.d.ts +21 -0
- package/dist/types/runtime/I18nLink.d.ts +8 -0
- package/dist/types/runtime/context.d.ts +38 -0
- package/dist/types/runtime/hooks.d.ts +28 -0
- package/dist/types/runtime/i18n/backend/config.d.ts +2 -0
- package/dist/types/runtime/i18n/backend/defaults.d.ts +13 -0
- package/dist/types/runtime/i18n/backend/defaults.node.d.ts +8 -0
- package/dist/types/runtime/i18n/backend/index.d.ts +3 -0
- package/dist/types/runtime/i18n/backend/middleware.common.d.ts +14 -0
- package/dist/types/runtime/i18n/backend/middleware.d.ts +12 -0
- package/dist/types/runtime/i18n/backend/middleware.node.d.ts +13 -0
- package/dist/types/runtime/i18n/backend/sdk-backend.d.ts +52 -0
- package/dist/types/runtime/i18n/detection/config.d.ts +11 -0
- package/dist/types/runtime/i18n/detection/index.d.ts +50 -0
- package/dist/types/runtime/i18n/detection/middleware.d.ts +24 -0
- package/dist/types/runtime/i18n/detection/middleware.node.d.ts +17 -0
- package/dist/types/runtime/i18n/index.d.ts +3 -0
- package/dist/types/runtime/i18n/instance.d.ts +93 -0
- package/dist/types/runtime/i18n/utils.d.ts +29 -0
- package/dist/types/runtime/index.d.ts +20 -0
- package/dist/types/runtime/types.d.ts +15 -0
- package/dist/types/runtime/utils.d.ts +33 -0
- package/dist/types/server/index.d.ts +8 -0
- package/dist/types/shared/deepMerge.d.ts +1 -0
- package/dist/types/shared/detection.d.ts +11 -0
- package/dist/types/shared/type.d.ts +156 -0
- package/dist/types/shared/utils.d.ts +5 -0
- package/package.json +100 -34
- package/rslib.config.mts +4 -0
- package/src/cli/index.ts +245 -0
- package/src/runtime/I18nLink.tsx +76 -0
- package/src/runtime/context.tsx +256 -0
- package/src/runtime/hooks.ts +274 -0
- package/src/runtime/i18n/backend/config.ts +10 -0
- package/src/runtime/i18n/backend/defaults.node.ts +31 -0
- package/src/runtime/i18n/backend/defaults.ts +37 -0
- package/src/runtime/i18n/backend/index.ts +181 -0
- package/src/runtime/i18n/backend/middleware.common.ts +116 -0
- package/src/runtime/i18n/backend/middleware.node.ts +32 -0
- package/src/runtime/i18n/backend/middleware.ts +28 -0
- package/src/runtime/i18n/backend/sdk-backend.ts +292 -0
- package/src/runtime/i18n/detection/config.ts +32 -0
- package/src/runtime/i18n/detection/index.ts +641 -0
- package/src/runtime/i18n/detection/middleware.node.ts +84 -0
- package/src/runtime/i18n/detection/middleware.ts +251 -0
- package/src/runtime/i18n/index.ts +8 -0
- package/src/runtime/i18n/instance.ts +227 -0
- package/src/runtime/i18n/utils.ts +333 -0
- package/src/runtime/index.tsx +281 -0
- package/src/runtime/types.ts +17 -0
- package/src/runtime/utils.ts +151 -0
- package/src/server/index.ts +336 -0
- package/src/shared/deepMerge.ts +38 -0
- package/src/shared/detection.ts +131 -0
- package/src/shared/type.ts +170 -0
- package/src/shared/utils.ts +82 -0
- package/tsconfig.json +12 -0
- package/dist/cjs/index.js +0 -73
- package/dist/cjs/languageDetector.js +0 -51
- package/dist/cjs/utils/index.js +0 -39
- package/dist/esm/index.js +0 -61
- package/dist/esm/languageDetector.js +0 -33
- package/dist/esm/utils/index.js +0 -16
- package/dist/esm-node/index.js +0 -49
- package/dist/esm-node/languageDetector.js +0 -26
- package/dist/esm-node/utils/index.js +0 -15
- package/dist/types/index.d.ts +0 -34
- package/dist/types/languageDetector.d.ts +0 -6
- package/dist/types/utils/index.d.ts +0 -5
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { isBrowser } from '@modern-js/runtime';
|
|
2
|
+
import LanguageDetector from 'i18next-browser-languagedetector';
|
|
3
|
+
import type { I18nInstance } from '../instance';
|
|
4
|
+
import { getActualI18nextInstance, isI18nWrapperInstance } from '../instance';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Register LanguageDetector plugin to i18n instance
|
|
8
|
+
* Must be called before init() to properly register the detector
|
|
9
|
+
* For wrapper instances, ensure detector is registered on the underlying i18next instance
|
|
10
|
+
*/
|
|
11
|
+
export const useI18nextLanguageDetector = (i18nInstance: I18nInstance) => {
|
|
12
|
+
if (!i18nInstance.isInitialized) {
|
|
13
|
+
// For wrapper instances, also register on the underlying instance
|
|
14
|
+
if (isI18nWrapperInstance(i18nInstance)) {
|
|
15
|
+
const actualInstance = getActualI18nextInstance(i18nInstance);
|
|
16
|
+
if (actualInstance && !actualInstance.isInitialized) {
|
|
17
|
+
actualInstance.use(LanguageDetector);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return i18nInstance.use(LanguageDetector);
|
|
21
|
+
}
|
|
22
|
+
return i18nInstance;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Read language directly from localStorage/cookie
|
|
27
|
+
* Fallback when detector is not available in services
|
|
28
|
+
*/
|
|
29
|
+
export const readLanguageFromStorage = (
|
|
30
|
+
detectionOptions?: any,
|
|
31
|
+
): string | undefined => {
|
|
32
|
+
try {
|
|
33
|
+
const options = detectionOptions || {};
|
|
34
|
+
const order = options.order || [
|
|
35
|
+
'querystring',
|
|
36
|
+
'cookie',
|
|
37
|
+
'localStorage',
|
|
38
|
+
'navigator',
|
|
39
|
+
'htmlTag',
|
|
40
|
+
'path',
|
|
41
|
+
'subdomain',
|
|
42
|
+
];
|
|
43
|
+
|
|
44
|
+
// Follow the detection order
|
|
45
|
+
for (const method of order) {
|
|
46
|
+
switch (method) {
|
|
47
|
+
case 'querystring': {
|
|
48
|
+
const lookupKey = options.lookupQuerystring || 'lng';
|
|
49
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
50
|
+
const lang = urlParams.get(lookupKey);
|
|
51
|
+
if (lang) {
|
|
52
|
+
return lang;
|
|
53
|
+
}
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
case 'cookie': {
|
|
57
|
+
const lookupKey = options.lookupCookie || 'i18next';
|
|
58
|
+
const cookies = document.cookie
|
|
59
|
+
.split(';')
|
|
60
|
+
.reduce((acc: Record<string, string>, item: string) => {
|
|
61
|
+
const [key, value] = item.trim().split('=');
|
|
62
|
+
if (key && value) {
|
|
63
|
+
acc[key] = decodeURIComponent(value);
|
|
64
|
+
}
|
|
65
|
+
return acc;
|
|
66
|
+
}, {});
|
|
67
|
+
if (cookies[lookupKey]) {
|
|
68
|
+
return cookies[lookupKey];
|
|
69
|
+
}
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
case 'localStorage': {
|
|
73
|
+
const lookupKey = options.lookupLocalStorage || 'i18nextLng';
|
|
74
|
+
const keysToCheck = [lookupKey];
|
|
75
|
+
if (lookupKey === 'i18nextLng') {
|
|
76
|
+
keysToCheck.push('i18next');
|
|
77
|
+
}
|
|
78
|
+
for (const key of keysToCheck) {
|
|
79
|
+
const stored = localStorage.getItem(key);
|
|
80
|
+
if (stored) {
|
|
81
|
+
return stored;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
case 'navigator': {
|
|
87
|
+
if (navigator.language) {
|
|
88
|
+
return navigator.language.split('-')[0];
|
|
89
|
+
}
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
case 'htmlTag': {
|
|
93
|
+
const htmlLang = document.documentElement.lang;
|
|
94
|
+
if (htmlLang) {
|
|
95
|
+
return htmlLang.split('-')[0];
|
|
96
|
+
}
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
} catch (error) {
|
|
102
|
+
// Ignore errors
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return undefined;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Detect language using i18next-browser-languagedetector
|
|
110
|
+
* For initialized instances without detector in services, manually create a detector instance
|
|
111
|
+
* For wrapper instances, access the underlying i18next instance's services
|
|
112
|
+
*/
|
|
113
|
+
export const detectLanguage = (
|
|
114
|
+
i18nInstance: I18nInstance,
|
|
115
|
+
_request?: any,
|
|
116
|
+
detectionOptions?: any,
|
|
117
|
+
): string | undefined => {
|
|
118
|
+
try {
|
|
119
|
+
// For wrapper instances, get the underlying i18next instance
|
|
120
|
+
const actualInstance = isI18nWrapperInstance(i18nInstance)
|
|
121
|
+
? getActualI18nextInstance(i18nInstance)
|
|
122
|
+
: i18nInstance;
|
|
123
|
+
|
|
124
|
+
// Check if either instance is initialized
|
|
125
|
+
const isInitialized =
|
|
126
|
+
i18nInstance.isInitialized || actualInstance?.isInitialized;
|
|
127
|
+
|
|
128
|
+
// Try to get detector from services (prefer actual instance for wrapper)
|
|
129
|
+
const detector =
|
|
130
|
+
actualInstance?.services?.languageDetector ||
|
|
131
|
+
i18nInstance.services?.languageDetector;
|
|
132
|
+
if (detector && typeof detector.detect === 'function') {
|
|
133
|
+
const result = detector.detect();
|
|
134
|
+
if (typeof result === 'string') {
|
|
135
|
+
return result;
|
|
136
|
+
}
|
|
137
|
+
if (Array.isArray(result) && result.length > 0) {
|
|
138
|
+
return result[0];
|
|
139
|
+
}
|
|
140
|
+
// If detector exists but returns undefined, continue to fallback logic
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Fallback: read directly from storage (always try this in browser)
|
|
144
|
+
// This is important for wrapper instances where detector might not be properly initialized
|
|
145
|
+
if (isBrowser()) {
|
|
146
|
+
const directRead = readLanguageFromStorage(detectionOptions);
|
|
147
|
+
if (directRead) {
|
|
148
|
+
return directRead;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// If instance is initialized, try creating manual detector
|
|
153
|
+
if (isInitialized) {
|
|
154
|
+
// Use actual instance's services/options for wrapper, otherwise use wrapper's
|
|
155
|
+
const servicesToUse = actualInstance?.services || i18nInstance.services;
|
|
156
|
+
const optionsToUse = actualInstance?.options || i18nInstance.options;
|
|
157
|
+
|
|
158
|
+
if (servicesToUse && optionsToUse) {
|
|
159
|
+
const manualDetector = new LanguageDetector();
|
|
160
|
+
const mergedOptions = detectionOptions
|
|
161
|
+
? { ...optionsToUse, detection: detectionOptions }
|
|
162
|
+
: optionsToUse;
|
|
163
|
+
manualDetector.init(servicesToUse, mergedOptions as any);
|
|
164
|
+
|
|
165
|
+
const result = manualDetector.detect();
|
|
166
|
+
if (typeof result === 'string') {
|
|
167
|
+
return result;
|
|
168
|
+
}
|
|
169
|
+
if (Array.isArray(result) && result.length > 0) {
|
|
170
|
+
return result[0];
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
} catch (error) {
|
|
175
|
+
return undefined;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return undefined;
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Cache user language to localStorage/cookie
|
|
183
|
+
* Uses LanguageDetector's cacheUserLanguage method when available
|
|
184
|
+
* For wrapper instances, access the underlying i18next instance's services
|
|
185
|
+
*/
|
|
186
|
+
export const cacheUserLanguage = (
|
|
187
|
+
i18nInstance: I18nInstance,
|
|
188
|
+
language: string,
|
|
189
|
+
detectionOptions?: any,
|
|
190
|
+
): void => {
|
|
191
|
+
if (typeof window === 'undefined') {
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
try {
|
|
196
|
+
// For wrapper instances, get the underlying i18next instance
|
|
197
|
+
const actualInstance = isI18nWrapperInstance(i18nInstance)
|
|
198
|
+
? getActualI18nextInstance(i18nInstance)
|
|
199
|
+
: i18nInstance;
|
|
200
|
+
|
|
201
|
+
// Try to use detector's cacheUserLanguage method first
|
|
202
|
+
// Prefer actual instance's detector for wrapper instances
|
|
203
|
+
const detector =
|
|
204
|
+
actualInstance?.services?.languageDetector ||
|
|
205
|
+
i18nInstance.services?.languageDetector;
|
|
206
|
+
if (detector && typeof detector.cacheUserLanguage === 'function') {
|
|
207
|
+
try {
|
|
208
|
+
detector.cacheUserLanguage(language);
|
|
209
|
+
return;
|
|
210
|
+
} catch (error) {
|
|
211
|
+
if (process.env.NODE_ENV === 'development') {
|
|
212
|
+
console.warn(
|
|
213
|
+
'[i18n] Failed to cache via detector, falling back to manual cache:',
|
|
214
|
+
error,
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Fallback: manually create detector instance if i18n is initialized
|
|
221
|
+
const isInitialized =
|
|
222
|
+
i18nInstance.isInitialized || actualInstance?.isInitialized;
|
|
223
|
+
const servicesToUse = actualInstance?.services || i18nInstance.services;
|
|
224
|
+
const optionsToUse = actualInstance?.options || i18nInstance.options;
|
|
225
|
+
|
|
226
|
+
if (isInitialized && servicesToUse && optionsToUse) {
|
|
227
|
+
try {
|
|
228
|
+
const userOptions = detectionOptions || optionsToUse?.detection;
|
|
229
|
+
const mergedOptions = userOptions
|
|
230
|
+
? { ...optionsToUse, detection: userOptions }
|
|
231
|
+
: optionsToUse;
|
|
232
|
+
|
|
233
|
+
const manualDetector = new LanguageDetector();
|
|
234
|
+
manualDetector.init(servicesToUse, mergedOptions as any);
|
|
235
|
+
|
|
236
|
+
if (typeof manualDetector.cacheUserLanguage === 'function') {
|
|
237
|
+
manualDetector.cacheUserLanguage(language);
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
} catch (error) {
|
|
241
|
+
if (process.env.NODE_ENV === 'development') {
|
|
242
|
+
console.warn('[i18n] Failed to create manual detector:', error);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
} catch (error) {
|
|
247
|
+
if (process.env.NODE_ENV === 'development') {
|
|
248
|
+
console.error('Failed to cache user language:', error);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
};
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import type { BaseBackendOptions } from '../../shared/type';
|
|
2
|
+
|
|
3
|
+
export interface I18nResourceStore {
|
|
4
|
+
data?: {
|
|
5
|
+
[language: string]: {
|
|
6
|
+
[namespace: string]: string | { [key: string]: any };
|
|
7
|
+
};
|
|
8
|
+
};
|
|
9
|
+
addResourceBundle?: (
|
|
10
|
+
language: string,
|
|
11
|
+
namespace: string,
|
|
12
|
+
resources: Record<string, string>,
|
|
13
|
+
deep?: boolean,
|
|
14
|
+
overwrite?: boolean,
|
|
15
|
+
) => void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function isI18nWrapperInstance(obj: any): boolean {
|
|
19
|
+
if (!obj || typeof obj !== 'object') {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
if (!obj.i18nInstance || typeof obj.i18nInstance !== 'object') {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
if (!obj.i18nInstance.instance) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
if (typeof obj.init !== 'function' || typeof obj.use !== 'function') {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function getI18nWrapperI18nextInstance(wrapperInstance: any): any {
|
|
35
|
+
if (isI18nWrapperInstance(wrapperInstance)) {
|
|
36
|
+
return wrapperInstance.i18nInstance?.instance;
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function getActualI18nextInstance(instance: I18nInstance | any): any {
|
|
42
|
+
if (isI18nWrapperInstance(instance)) {
|
|
43
|
+
const i18nextInstance = getI18nWrapperI18nextInstance(instance);
|
|
44
|
+
return i18nextInstance || instance;
|
|
45
|
+
}
|
|
46
|
+
return instance;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface I18nInstance {
|
|
50
|
+
language: string;
|
|
51
|
+
isInitialized: boolean;
|
|
52
|
+
init: {
|
|
53
|
+
(callback?: (error: any, t: any) => void): Promise<any>;
|
|
54
|
+
(
|
|
55
|
+
options: I18nInitOptions,
|
|
56
|
+
callback?: (error: any, t: any) => void,
|
|
57
|
+
): Promise<any>;
|
|
58
|
+
};
|
|
59
|
+
changeLanguage?: (
|
|
60
|
+
lng?: string,
|
|
61
|
+
callback?: (error: any, t: any) => void,
|
|
62
|
+
) => Promise<any>;
|
|
63
|
+
setLang?: (lang: string) => void | Promise<void>;
|
|
64
|
+
use: (plugin: any) => void;
|
|
65
|
+
createInstance: (options?: I18nInitOptions) => I18nInstance;
|
|
66
|
+
cloneInstance?: () => I18nInstance; // ssr need
|
|
67
|
+
// i18next store (may not be in type definition but exists at runtime)
|
|
68
|
+
store?: I18nResourceStore;
|
|
69
|
+
emit?: (event: string, ...args: any[]) => void;
|
|
70
|
+
reloadResources?: (language?: string, namespace?: string) => Promise<void>;
|
|
71
|
+
services?: {
|
|
72
|
+
languageDetector?: {
|
|
73
|
+
detect: (request?: any, options?: any) => string | string[] | undefined;
|
|
74
|
+
[key: string]: any;
|
|
75
|
+
};
|
|
76
|
+
resourceStore?: I18nResourceStore;
|
|
77
|
+
backend?: any; // Backend instance (e.g., SdkBackend)
|
|
78
|
+
[key: string]: any;
|
|
79
|
+
};
|
|
80
|
+
// i18next instance options (available after initialization)
|
|
81
|
+
options?: {
|
|
82
|
+
backend?: BackendOptions;
|
|
83
|
+
[key: string]: any;
|
|
84
|
+
};
|
|
85
|
+
[key: string]: any;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
type LanguageDetectorOrder = string[];
|
|
89
|
+
type LanguageDetectorCaches = boolean | string[];
|
|
90
|
+
export interface LanguageDetectorOptions {
|
|
91
|
+
order?: LanguageDetectorOrder;
|
|
92
|
+
lookupQuerystring?: string;
|
|
93
|
+
lookupCookie?: string;
|
|
94
|
+
lookupLocalStorage?: string;
|
|
95
|
+
lookupSession?: string;
|
|
96
|
+
lookupFromPathIndex?: number;
|
|
97
|
+
caches?: LanguageDetectorCaches;
|
|
98
|
+
cookieExpirationDate?: Date;
|
|
99
|
+
cookieDomain?: string;
|
|
100
|
+
lookupHeader?: string;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface BackendOptions extends Omit<BaseBackendOptions, 'enabled'> {
|
|
104
|
+
parse?: (data: string) => any;
|
|
105
|
+
stringify?: (data: any) => string;
|
|
106
|
+
[key: string]: any;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export interface Resources {
|
|
110
|
+
[lng: string]: {
|
|
111
|
+
[source: string]: string | Record<string, string>;
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export type I18nInitOptions = {
|
|
116
|
+
lng?: string;
|
|
117
|
+
fallbackLng?: string;
|
|
118
|
+
supportedLngs?: string[];
|
|
119
|
+
initImmediate?: boolean;
|
|
120
|
+
detection?: LanguageDetectorOptions;
|
|
121
|
+
backend?: BackendOptions;
|
|
122
|
+
resources?: Resources;
|
|
123
|
+
ns?: string | string[];
|
|
124
|
+
defaultNS?: string | string[];
|
|
125
|
+
interpolation?: {
|
|
126
|
+
escapeValue?: boolean;
|
|
127
|
+
[key: string]: any;
|
|
128
|
+
};
|
|
129
|
+
react?: {
|
|
130
|
+
useSuspense?: boolean;
|
|
131
|
+
[key: string]: any;
|
|
132
|
+
};
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
export function isI18nInstance(obj: any): obj is I18nInstance {
|
|
136
|
+
if (!obj || typeof obj !== 'object') {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (isI18nWrapperInstance(obj)) {
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return typeof obj.init === 'function' && typeof obj.use === 'function';
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async function tryImportI18next(): Promise<I18nInstance | null> {
|
|
148
|
+
try {
|
|
149
|
+
const i18next = await import('i18next');
|
|
150
|
+
return i18next.default as unknown as I18nInstance;
|
|
151
|
+
} catch (error) {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
async function createI18nextInstance(): Promise<I18nInstance | null> {
|
|
157
|
+
try {
|
|
158
|
+
const i18next = await tryImportI18next();
|
|
159
|
+
if (!i18next) {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
return i18next.createInstance({
|
|
163
|
+
initImmediate: false,
|
|
164
|
+
}) as unknown as I18nInstance;
|
|
165
|
+
} catch (error) {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
async function tryImportReactI18next() {
|
|
171
|
+
try {
|
|
172
|
+
const reactI18next = await import('react-i18next');
|
|
173
|
+
return reactI18next;
|
|
174
|
+
} catch (error) {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export function getI18nextInstanceForProvider(
|
|
180
|
+
instance: I18nInstance | any,
|
|
181
|
+
): any {
|
|
182
|
+
if (isI18nWrapperInstance(instance)) {
|
|
183
|
+
const i18nextInstance = getI18nWrapperI18nextInstance(instance);
|
|
184
|
+
if (i18nextInstance) {
|
|
185
|
+
return i18nextInstance;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
return instance;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export async function getI18nInstance(
|
|
193
|
+
userInstance?: I18nInstance | any,
|
|
194
|
+
): Promise<I18nInstance> {
|
|
195
|
+
if (userInstance) {
|
|
196
|
+
if (isI18nWrapperInstance(userInstance)) {
|
|
197
|
+
return userInstance as I18nInstance;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (isI18nInstance(userInstance)) {
|
|
201
|
+
return userInstance;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const i18nextInstance = await createI18nextInstance();
|
|
206
|
+
if (i18nextInstance) {
|
|
207
|
+
return i18nextInstance;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
throw new Error('No i18n instance found');
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export async function getInitReactI18next() {
|
|
214
|
+
const reactI18nextModule = await tryImportReactI18next();
|
|
215
|
+
if (reactI18nextModule) {
|
|
216
|
+
return reactI18nextModule.initReactI18next;
|
|
217
|
+
}
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export async function getI18nextProvider() {
|
|
222
|
+
const reactI18nextModule = await tryImportReactI18next();
|
|
223
|
+
if (reactI18nextModule) {
|
|
224
|
+
return reactI18nextModule.I18nextProvider;
|
|
225
|
+
}
|
|
226
|
+
return null;
|
|
227
|
+
}
|