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.
Files changed (47) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +0 -2
  3. package/dist/amd/react-i18next.js +134 -176
  4. package/dist/amd/react-i18next.min.js +1 -1
  5. package/dist/commonjs/Trans.js +2 -2
  6. package/dist/commonjs/TransWithoutContext.js +53 -55
  7. package/dist/commonjs/Translation.js +6 -5
  8. package/dist/commonjs/context.js +17 -25
  9. package/dist/commonjs/defaults.js +6 -7
  10. package/dist/commonjs/i18nInstance.js +6 -7
  11. package/dist/commonjs/useSSR.js +5 -4
  12. package/dist/commonjs/useTranslation.js +17 -20
  13. package/dist/commonjs/utils.js +28 -45
  14. package/dist/commonjs/withSSR.js +19 -20
  15. package/dist/commonjs/withTranslation.js +4 -3
  16. package/dist/es/I18nextProvider.js +5 -6
  17. package/dist/es/Trans.js +18 -19
  18. package/dist/es/TransWithoutContext.js +68 -72
  19. package/dist/es/Translation.js +6 -7
  20. package/dist/es/context.js +13 -22
  21. package/dist/es/defaults.js +3 -6
  22. package/dist/es/i18nInstance.js +3 -5
  23. package/dist/es/package.json +1 -1
  24. package/dist/es/useSSR.js +3 -4
  25. package/dist/es/useTranslation.js +16 -21
  26. package/dist/es/utils.js +19 -46
  27. package/dist/es/withSSR.js +16 -19
  28. package/dist/es/withTranslation.js +28 -32
  29. package/dist/umd/react-i18next.js +134 -176
  30. package/dist/umd/react-i18next.min.js +1 -1
  31. package/icu.macro.d.ts +5 -5
  32. package/index.d.ts +2 -2
  33. package/package.json +23 -30
  34. package/react-i18next.js +134 -176
  35. package/react-i18next.min.js +1 -1
  36. package/src/Trans.js +2 -3
  37. package/src/TransWithoutContext.js +56 -62
  38. package/src/Translation.js +2 -3
  39. package/src/context.js +13 -36
  40. package/src/defaults.js +3 -5
  41. package/src/i18nInstance.js +3 -5
  42. package/src/useSSR.js +3 -3
  43. package/src/useTranslation.js +25 -24
  44. package/src/utils.js +26 -76
  45. package/src/withSSR.js +2 -3
  46. package/src/withTranslation.js +2 -3
  47. 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
- function alwaysNewT(i18n, language, namespace, keyPrefix) {
12
- return i18n.getFixedT(language, namespace, keyPrefix);
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 (typeof optsOrDefaultValue === 'string') return optsOrDefaultValue;
32
- if (optsOrDefaultValue && typeof optsOrDefaultValue === 'object' && typeof optsOrDefaultValue.defaultValue === 'string') return optsOrDefaultValue.defaultValue;
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 && i18n.options.react.wait !== undefined) warnOnce('It seems you are still using the old wait option, you may migrate to the new useSuspense behaviour.');
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 && i18n.options.defaultNS;
52
- namespaces = typeof namespaces === 'string' ? [namespaces] : namespaces || ['translation'];
53
- if (i18n.reportNamespaces.addUsedNamespaces) i18n.reportNamespaces.addUsedNamespaces(namespaces);
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
- function boundReset() {
78
+ const boundReset = () => {
84
79
  if (isMounted.current) setT(getNewT);
85
- }
86
- if (bindI18n && i18n) i18n.on(bindI18n, boundReset);
87
- if (bindI18nStore && i18n) i18n.store.on(bindI18nStore, boundReset);
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 (bindI18n && i18n) bindI18n.split(' ').forEach(e => i18n.off(e, boundReset));
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 function warn() {
2
- if (console && console.warn) {
3
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
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 function warnOnce() {
12
- for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
13
- args[_key2] = arguments[_key2];
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 function loadNamespaces(i18n, ns, cb) {
26
+ export const loadNamespaces = (i18n, ns, cb) => {
33
27
  i18n.loadNamespaces(ns, loadedClb(i18n, cb));
34
- }
35
- export function loadLanguages(i18n, lng, ns, cb) {
36
- if (typeof ns === 'string') ns = [ns];
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
- function oldI18nextHasLoadedNamespace(ns, i18n) {
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 && options.bindI18n.indexOf('languageChanging') > -1 && i18nInstance.services.backendConnector.backend && i18nInstance.isLanguageChangingTo && !loadNotPending(i18nInstance.isLanguageChangingTo, ns)) return false;
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 function getDisplayName(Component) {
76
- return Component.displayName || Component.name || (typeof Component === 'string' && Component.length > 0 ? Component : 'Unknown');
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;
@@ -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 function withSSR() {
6
- return function Extend(WrappedComponent) {
7
- function I18nextWithSSR(_ref) {
8
- let {
9
- initialI18nStore,
10
- initialLanguage,
11
- ...rest
12
- } = _ref;
13
- useSSR(initialI18nStore, initialLanguage);
14
- return createElement(WrappedComponent, {
15
- ...rest
16
- });
17
- }
18
- I18nextWithSSR.getInitialProps = composeInitialProps(WrappedComponent);
19
- I18nextWithSSR.displayName = `withI18nextSSR(${getDisplayName(WrappedComponent)})`;
20
- I18nextWithSSR.WrappedComponent = WrappedComponent;
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 function withTranslation(ns) {
5
- let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
6
- return function Extend(WrappedComponent) {
7
- function I18nextWithTranslation(_ref) {
8
- let {
9
- forwardedRef,
10
- ...rest
11
- } = _ref;
12
- const [t, i18n, ready] = useTranslation(ns, {
13
- ...rest,
14
- keyPrefix: options.keyPrefix
15
- });
16
- const passDownProps = {
17
- ...rest,
18
- t,
19
- i18n,
20
- tReady: ready
21
- };
22
- if (options.withRef && forwardedRef) {
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
- I18nextWithTranslation.displayName = `withI18nextTranslation(${getDisplayName(WrappedComponent)})`;
30
- I18nextWithTranslation.WrappedComponent = WrappedComponent;
31
- const forwardRef = (props, ref) => createElement(I18nextWithTranslation, Object.assign({}, props, {
32
- forwardedRef: ref
33
- }));
34
- return options.withRef ? forwardRefReact(forwardRef) : I18nextWithTranslation;
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
+ };