react-i18next 14.1.2 → 15.0.0
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/CHANGELOG.md +16 -0
- package/README.md +0 -2
- package/dist/amd/react-i18next.js +134 -176
- package/dist/amd/react-i18next.min.js +1 -1
- package/dist/commonjs/Trans.js +2 -2
- package/dist/commonjs/TransWithoutContext.js +53 -55
- package/dist/commonjs/Translation.js +6 -5
- package/dist/commonjs/context.js +17 -25
- package/dist/commonjs/defaults.js +6 -7
- package/dist/commonjs/i18nInstance.js +6 -7
- package/dist/commonjs/useSSR.js +5 -4
- package/dist/commonjs/useTranslation.js +17 -20
- package/dist/commonjs/utils.js +28 -45
- package/dist/commonjs/withSSR.js +19 -20
- package/dist/commonjs/withTranslation.js +4 -3
- package/dist/es/I18nextProvider.js +5 -6
- package/dist/es/Trans.js +18 -19
- package/dist/es/TransWithoutContext.js +68 -72
- package/dist/es/Translation.js +6 -7
- package/dist/es/context.js +13 -22
- package/dist/es/defaults.js +3 -6
- package/dist/es/i18nInstance.js +3 -5
- package/dist/es/package.json +1 -1
- package/dist/es/useSSR.js +3 -4
- package/dist/es/useTranslation.js +16 -21
- package/dist/es/utils.js +19 -46
- package/dist/es/withSSR.js +16 -19
- package/dist/es/withTranslation.js +28 -32
- package/dist/umd/react-i18next.js +134 -176
- package/dist/umd/react-i18next.min.js +1 -1
- package/icu.macro.d.ts +5 -5
- package/index.d.ts +2 -2
- package/package.json +23 -30
- package/react-i18next.js +134 -176
- package/react-i18next.min.js +1 -1
- package/src/Trans.js +2 -3
- package/src/TransWithoutContext.js +56 -62
- package/src/Translation.js +2 -3
- package/src/context.js +13 -36
- package/src/defaults.js +3 -5
- package/src/i18nInstance.js +3 -5
- package/src/useSSR.js +3 -3
- package/src/useTranslation.js +25 -24
- package/src/utils.js +26 -76
- package/src/withSSR.js +2 -3
- package/src/withTranslation.js +2 -3
- package/vitest.workspace.typescript.mts +11 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useState, useEffect, useContext, useRef, useCallback } from 'react';
|
|
2
2
|
import { getI18n, getDefaults, ReportNamespaces, I18nContext } from './context.js';
|
|
3
|
-
import { warnOnce, loadNamespaces, loadLanguages, hasLoadedNamespace } from './utils.js';
|
|
3
|
+
import { warnOnce, loadNamespaces, loadLanguages, hasLoadedNamespace, isString, isObject } from './utils.js';
|
|
4
4
|
const usePrevious = (value, ignore) => {
|
|
5
5
|
const ref = useRef();
|
|
6
6
|
useEffect(() => {
|
|
@@ -8,14 +8,9 @@ const usePrevious = (value, ignore) => {
|
|
|
8
8
|
}, [value, ignore]);
|
|
9
9
|
return ref.current;
|
|
10
10
|
};
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
function useMemoizedT(i18n, language, namespace, keyPrefix) {
|
|
15
|
-
return useCallback(alwaysNewT(i18n, language, namespace, keyPrefix), [i18n, language, namespace, keyPrefix]);
|
|
16
|
-
}
|
|
17
|
-
export function useTranslation(ns) {
|
|
18
|
-
let props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
11
|
+
const alwaysNewT = (i18n, language, namespace, keyPrefix) => i18n.getFixedT(language, namespace, keyPrefix);
|
|
12
|
+
const useMemoizedT = (i18n, language, namespace, keyPrefix) => useCallback(alwaysNewT(i18n, language, namespace, keyPrefix), [i18n, language, namespace, keyPrefix]);
|
|
13
|
+
export const useTranslation = (ns, props = {}) => {
|
|
19
14
|
const {
|
|
20
15
|
i18n: i18nFromProps
|
|
21
16
|
} = props;
|
|
@@ -28,8 +23,8 @@ export function useTranslation(ns) {
|
|
|
28
23
|
if (!i18n) {
|
|
29
24
|
warnOnce('You will need to pass in an i18next instance by using initReactI18next');
|
|
30
25
|
const notReadyT = (k, optsOrDefaultValue) => {
|
|
31
|
-
if (
|
|
32
|
-
if (optsOrDefaultValue &&
|
|
26
|
+
if (isString(optsOrDefaultValue)) return optsOrDefaultValue;
|
|
27
|
+
if (isObject(optsOrDefaultValue) && isString(optsOrDefaultValue.defaultValue)) return optsOrDefaultValue.defaultValue;
|
|
33
28
|
return Array.isArray(k) ? k[k.length - 1] : k;
|
|
34
29
|
};
|
|
35
30
|
const retNotReady = [notReadyT, {}, false];
|
|
@@ -38,7 +33,7 @@ export function useTranslation(ns) {
|
|
|
38
33
|
retNotReady.ready = false;
|
|
39
34
|
return retNotReady;
|
|
40
35
|
}
|
|
41
|
-
if (i18n.options.react
|
|
36
|
+
if (i18n.options.react?.wait) warnOnce('It seems you are still using the old wait option, you may migrate to the new useSuspense behaviour.');
|
|
42
37
|
const i18nOptions = {
|
|
43
38
|
...getDefaults(),
|
|
44
39
|
...i18n.options.react,
|
|
@@ -48,9 +43,9 @@ export function useTranslation(ns) {
|
|
|
48
43
|
useSuspense,
|
|
49
44
|
keyPrefix
|
|
50
45
|
} = i18nOptions;
|
|
51
|
-
let namespaces = ns || defaultNSFromContext || i18n.options
|
|
52
|
-
namespaces =
|
|
53
|
-
|
|
46
|
+
let namespaces = ns || defaultNSFromContext || i18n.options?.defaultNS;
|
|
47
|
+
namespaces = isString(namespaces) ? [namespaces] : namespaces || ['translation'];
|
|
48
|
+
i18n.reportNamespaces.addUsedNamespaces?.(namespaces);
|
|
54
49
|
const ready = (i18n.isInitialized || i18n.initializedStoreOnce) && namespaces.every(n => hasLoadedNamespace(n, i18n, i18nOptions));
|
|
55
50
|
const memoGetT = useMemoizedT(i18n, props.lng || null, i18nOptions.nsMode === 'fallback' ? namespaces : namespaces[0], keyPrefix);
|
|
56
51
|
const getT = () => memoGetT;
|
|
@@ -80,14 +75,14 @@ export function useTranslation(ns) {
|
|
|
80
75
|
if (ready && previousJoinedNS && previousJoinedNS !== joinedNS && isMounted.current) {
|
|
81
76
|
setT(getNewT);
|
|
82
77
|
}
|
|
83
|
-
|
|
78
|
+
const boundReset = () => {
|
|
84
79
|
if (isMounted.current) setT(getNewT);
|
|
85
|
-
}
|
|
86
|
-
if (bindI18n
|
|
87
|
-
if (bindI18nStore
|
|
80
|
+
};
|
|
81
|
+
if (bindI18n) i18n?.on(bindI18n, boundReset);
|
|
82
|
+
if (bindI18nStore) i18n?.store.on(bindI18nStore, boundReset);
|
|
88
83
|
return () => {
|
|
89
84
|
isMounted.current = false;
|
|
90
|
-
if (
|
|
85
|
+
if (i18n) bindI18n?.split(' ').forEach(e => i18n.off(e, boundReset));
|
|
91
86
|
if (bindI18nStore && i18n) bindI18nStore.split(' ').forEach(e => i18n.store.off(e, boundReset));
|
|
92
87
|
};
|
|
93
88
|
}, [i18n, joinedNS]);
|
|
@@ -109,4 +104,4 @@ export function useTranslation(ns) {
|
|
|
109
104
|
loadNamespaces(i18n, namespaces, () => resolve());
|
|
110
105
|
}
|
|
111
106
|
});
|
|
112
|
-
}
|
|
107
|
+
};
|
package/dist/es/utils.js
CHANGED
|
@@ -1,21 +1,15 @@
|
|
|
1
|
-
export
|
|
2
|
-
if (console
|
|
3
|
-
|
|
4
|
-
args[_key] = arguments[_key];
|
|
5
|
-
}
|
|
6
|
-
if (typeof args[0] === 'string') args[0] = `react-i18next:: ${args[0]}`;
|
|
1
|
+
export const warn = (...args) => {
|
|
2
|
+
if (console?.warn) {
|
|
3
|
+
if (isString(args[0])) args[0] = `react-i18next:: ${args[0]}`;
|
|
7
4
|
console.warn(...args);
|
|
8
5
|
}
|
|
9
|
-
}
|
|
6
|
+
};
|
|
10
7
|
const alreadyWarned = {};
|
|
11
|
-
export
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
if (typeof args[0] === 'string' && alreadyWarned[args[0]]) return;
|
|
16
|
-
if (typeof args[0] === 'string') alreadyWarned[args[0]] = new Date();
|
|
8
|
+
export const warnOnce = (...args) => {
|
|
9
|
+
if (isString(args[0]) && alreadyWarned[args[0]]) return;
|
|
10
|
+
if (isString(args[0])) alreadyWarned[args[0]] = new Date();
|
|
17
11
|
warn(...args);
|
|
18
|
-
}
|
|
12
|
+
};
|
|
19
13
|
const loadedClb = (i18n, cb) => () => {
|
|
20
14
|
if (i18n.isInitialized) {
|
|
21
15
|
cb();
|
|
@@ -29,49 +23,28 @@ const loadedClb = (i18n, cb) => () => {
|
|
|
29
23
|
i18n.on('initialized', initialized);
|
|
30
24
|
}
|
|
31
25
|
};
|
|
32
|
-
export
|
|
26
|
+
export const loadNamespaces = (i18n, ns, cb) => {
|
|
33
27
|
i18n.loadNamespaces(ns, loadedClb(i18n, cb));
|
|
34
|
-
}
|
|
35
|
-
export
|
|
36
|
-
if (
|
|
28
|
+
};
|
|
29
|
+
export const loadLanguages = (i18n, lng, ns, cb) => {
|
|
30
|
+
if (isString(ns)) ns = [ns];
|
|
37
31
|
ns.forEach(n => {
|
|
38
32
|
if (i18n.options.ns.indexOf(n) < 0) i18n.options.ns.push(n);
|
|
39
33
|
});
|
|
40
34
|
i18n.loadLanguages(lng, loadedClb(i18n, cb));
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
44
|
-
const lng = i18n.languages[0];
|
|
45
|
-
const fallbackLng = i18n.options ? i18n.options.fallbackLng : false;
|
|
46
|
-
const lastLng = i18n.languages[i18n.languages.length - 1];
|
|
47
|
-
if (lng.toLowerCase() === 'cimode') return true;
|
|
48
|
-
const loadNotPending = (l, n) => {
|
|
49
|
-
const loadState = i18n.services.backendConnector.state[`${l}|${n}`];
|
|
50
|
-
return loadState === -1 || loadState === 2;
|
|
51
|
-
};
|
|
52
|
-
if (options.bindI18n && options.bindI18n.indexOf('languageChanging') > -1 && i18n.services.backendConnector.backend && i18n.isLanguageChangingTo && !loadNotPending(i18n.isLanguageChangingTo, ns)) return false;
|
|
53
|
-
if (i18n.hasResourceBundle(lng, ns)) return true;
|
|
54
|
-
if (!i18n.services.backendConnector.backend || i18n.options.resources && !i18n.options.partialBundledLanguages) return true;
|
|
55
|
-
if (loadNotPending(lng, ns) && (!fallbackLng || loadNotPending(lastLng, ns))) return true;
|
|
56
|
-
return false;
|
|
57
|
-
}
|
|
58
|
-
export function hasLoadedNamespace(ns, i18n) {
|
|
59
|
-
let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
35
|
+
};
|
|
36
|
+
export const hasLoadedNamespace = (ns, i18n, options = {}) => {
|
|
60
37
|
if (!i18n.languages || !i18n.languages.length) {
|
|
61
38
|
warnOnce('i18n.languages were undefined or empty', i18n.languages);
|
|
62
39
|
return true;
|
|
63
40
|
}
|
|
64
|
-
const isNewerI18next = i18n.options.ignoreJSONStructure !== undefined;
|
|
65
|
-
if (!isNewerI18next) {
|
|
66
|
-
return oldI18nextHasLoadedNamespace(ns, i18n, options);
|
|
67
|
-
}
|
|
68
41
|
return i18n.hasLoadedNamespace(ns, {
|
|
69
42
|
lng: options.lng,
|
|
70
43
|
precheck: (i18nInstance, loadNotPending) => {
|
|
71
|
-
if (options.bindI18n
|
|
44
|
+
if (options.bindI18n?.indexOf('languageChanging') > -1 && i18nInstance.services.backendConnector.backend && i18nInstance.isLanguageChangingTo && !loadNotPending(i18nInstance.isLanguageChangingTo, ns)) return false;
|
|
72
45
|
}
|
|
73
46
|
});
|
|
74
|
-
}
|
|
75
|
-
export
|
|
76
|
-
|
|
77
|
-
|
|
47
|
+
};
|
|
48
|
+
export const getDisplayName = Component => Component.displayName || Component.name || (isString(Component) && Component.length > 0 ? Component : 'Unknown');
|
|
49
|
+
export const isString = obj => typeof obj === 'string';
|
|
50
|
+
export const isObject = obj => typeof obj === 'object' && obj !== null;
|
package/dist/es/withSSR.js
CHANGED
|
@@ -2,22 +2,19 @@ import { createElement } from 'react';
|
|
|
2
2
|
import { useSSR } from './useSSR.js';
|
|
3
3
|
import { composeInitialProps } from './context.js';
|
|
4
4
|
import { getDisplayName } from './utils.js';
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
return I18nextWithSSR;
|
|
22
|
-
};
|
|
23
|
-
}
|
|
5
|
+
export const withSSR = () => function Extend(WrappedComponent) {
|
|
6
|
+
function I18nextWithSSR({
|
|
7
|
+
initialI18nStore,
|
|
8
|
+
initialLanguage,
|
|
9
|
+
...rest
|
|
10
|
+
}) {
|
|
11
|
+
useSSR(initialI18nStore, initialLanguage);
|
|
12
|
+
return createElement(WrappedComponent, {
|
|
13
|
+
...rest
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
I18nextWithSSR.getInitialProps = composeInitialProps(WrappedComponent);
|
|
17
|
+
I18nextWithSSR.displayName = `withI18nextSSR(${getDisplayName(WrappedComponent)})`;
|
|
18
|
+
I18nextWithSSR.WrappedComponent = WrappedComponent;
|
|
19
|
+
return I18nextWithSSR;
|
|
20
|
+
};
|
|
@@ -1,36 +1,32 @@
|
|
|
1
1
|
import { createElement, forwardRef as forwardRefReact } from 'react';
|
|
2
2
|
import { useTranslation } from './useTranslation.js';
|
|
3
3
|
import { getDisplayName } from './utils.js';
|
|
4
|
-
export
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
passDownProps.ref = forwardedRef;
|
|
24
|
-
} else if (!options.withRef && forwardedRef) {
|
|
25
|
-
passDownProps.forwardedRef = forwardedRef;
|
|
26
|
-
}
|
|
27
|
-
return createElement(WrappedComponent, passDownProps);
|
|
4
|
+
export const withTranslation = (ns, options = {}) => function Extend(WrappedComponent) {
|
|
5
|
+
function I18nextWithTranslation({
|
|
6
|
+
forwardedRef,
|
|
7
|
+
...rest
|
|
8
|
+
}) {
|
|
9
|
+
const [t, i18n, ready] = useTranslation(ns, {
|
|
10
|
+
...rest,
|
|
11
|
+
keyPrefix: options.keyPrefix
|
|
12
|
+
});
|
|
13
|
+
const passDownProps = {
|
|
14
|
+
...rest,
|
|
15
|
+
t,
|
|
16
|
+
i18n,
|
|
17
|
+
tReady: ready
|
|
18
|
+
};
|
|
19
|
+
if (options.withRef && forwardedRef) {
|
|
20
|
+
passDownProps.ref = forwardedRef;
|
|
21
|
+
} else if (!options.withRef && forwardedRef) {
|
|
22
|
+
passDownProps.forwardedRef = forwardedRef;
|
|
28
23
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
};
|
|
36
|
-
|
|
24
|
+
return createElement(WrappedComponent, passDownProps);
|
|
25
|
+
}
|
|
26
|
+
I18nextWithTranslation.displayName = `withI18nextTranslation(${getDisplayName(WrappedComponent)})`;
|
|
27
|
+
I18nextWithTranslation.WrappedComponent = WrappedComponent;
|
|
28
|
+
const forwardRef = (props, ref) => createElement(I18nextWithTranslation, Object.assign({}, props, {
|
|
29
|
+
forwardedRef: ref
|
|
30
|
+
}));
|
|
31
|
+
return options.withRef ? forwardRefReact(forwardRef) : I18nextWithTranslation;
|
|
32
|
+
};
|