diff --git a/src/Trans.js b/src/Trans.js index b14cfd599..7f10ebe81 100644 --- a/src/Trans.js +++ b/src/Trans.js @@ -23,7 +23,7 @@ export function Trans({ const { i18n: i18nFromContext, defaultNS: defaultNSFromContext } = useContext(I18nContext) || {}; const i18n = i18nFromProps || i18nFromContext || getI18n(); - const t = tFromProps || (i18n && i18n.t.bind(i18n)); + const t = tFromProps || i18n?.t.bind(i18n); return TransWithoutContext({ children, @@ -36,8 +36,7 @@ export function Trans({ defaults, components, // prepare having a namespace - ns: - ns || (t && t.ns) || defaultNSFromContext || (i18n && i18n.options && i18n.options.defaultNS), + ns: ns || t?.ns || defaultNSFromContext || i18n?.options?.defaultNS, i18n, t: tFromProps, shouldUnescape, diff --git a/src/TransWithoutContext.js b/src/TransWithoutContext.js index a2858aeba..c10b57443 100644 --- a/src/TransWithoutContext.js +++ b/src/TransWithoutContext.js @@ -6,15 +6,15 @@ import { getI18n } from './i18nInstance.js'; const hasChildren = (node, checkLength) => { if (!node) return false; - const base = node.props ? node.props.children : node.children; + const base = node.props?.children ?? node.children; if (checkLength) return base.length > 0; return !!base; }; const getChildren = (node) => { if (!node) return []; - const children = node.props ? node.props.children : node.children; - return node.props && node.props.i18nIsDynamicList ? getAsArray(children) : children; + const children = node.props?.children ?? node.children; + return node.props?.i18nIsDynamicList ? getAsArray(children) : children; }; const hasValidReactChildren = (children) => @@ -35,10 +35,9 @@ export const nodesToString = (children, i18nOptions) => { // do not use `React.Children.toArray`, will fail at object children const childrenArray = getAsArray(children); - const keepArray = - i18nOptions.transSupportBasicHtmlNodes && i18nOptions.transKeepBasicHtmlNodesFor - ? i18nOptions.transKeepBasicHtmlNodesFor - : []; + const keepArray = i18nOptions?.transSupportBasicHtmlNodes + ? (i18nOptions.transKeepBasicHtmlNodesFor ?? []) + : []; // e.g. lorem
ipsum {{ messageCount, format }} dolor bold amet childrenArray.forEach((child, childIndex) => { @@ -141,7 +140,7 @@ const renderNodes = (children, targetString, i18n, i18nOptions, combinedTOpts, s // `mappedChildren` will always be empty if using the `i18nIsDynamicList` prop, // but the children might not necessarily be react components return (hasValidReactChildren(childs) && mappedChildren.length === 0) || - (child.props && child.props.i18nIsDynamicList) + child.props?.i18nIsDynamicList ? childs : mappedChildren; }; @@ -179,9 +178,7 @@ const renderNodes = (children, targetString, i18n, i18nOptions, combinedTOpts, s return astNodes.reduce((mem, node, i) => { const translationContent = - node.children && - node.children[0] && - node.children[0].content && + node.children?.[0]?.content && i18n.services.interpolator.interpolate(node.children[0].content, opts, i18n.language); if (node.type === 'tag') { @@ -326,10 +323,10 @@ export function Trans({ const t = tFromProps || i18n.t.bind(i18n) || ((k) => k); - const reactI18nextOptions = { ...getDefaults(), ...(i18n.options && i18n.options.react) }; + const reactI18nextOptions = { ...getDefaults(), ...i18n.options?.react }; // prepare having a namespace - let namespaces = ns || t.ns || (i18n.options && i18n.options.defaultNS); + let namespaces = ns || t.ns || i18n.options?.defaultNS; namespaces = isString(namespaces) ? [namespaces] : namespaces || ['translation']; const nodeAsString = nodesToString(children, reactI18nextOptions); @@ -339,7 +336,7 @@ export function Trans({ const key = i18nKey || (hashTransKey ? hashTransKey(nodeAsString || defaultValue) : nodeAsString || defaultValue); - if (i18n.options && i18n.options.interpolation && i18n.options.interpolation.defaultVariables) { + if (i18n.options?.interpolation?.defaultVariables) { // eslint-disable-next-line no-param-reassign values = values && Object.keys(values).length > 0 @@ -393,7 +390,7 @@ export function Trans({ // allows user to pass `null` to `parent` // and override `defaultTransParent` if is present - const useAsParent = parent !== undefined ? parent : reactI18nextOptions.defaultTransParent; + const useAsParent = parent ?? reactI18nextOptions.defaultTransParent; return useAsParent ? createElement(useAsParent, additionalProps, content) : content; } diff --git a/src/context.js b/src/context.js index 3b00a459f..8434992e0 100644 --- a/src/context.js +++ b/src/context.js @@ -14,7 +14,7 @@ export class ReportNamespaces { addUsedNamespaces(namespaces) { namespaces.forEach((ns) => { - if (!this.usedNamespaces[ns]) this.usedNamespaces[ns] = true; + this.usedNamespaces[ns] ??= true; }); } @@ -22,9 +22,7 @@ export class ReportNamespaces { } export const composeInitialProps = (ForComponent) => async (ctx) => { - const componentsInitialProps = ForComponent.getInitialProps - ? await ForComponent.getInitialProps(ctx) - : {}; + const componentsInitialProps = (await ForComponent.getInitialProps?.(ctx)) ?? {}; const i18nInitialProps = getInitialProps(); @@ -36,7 +34,7 @@ export const composeInitialProps = (ForComponent) => async (ctx) => { export const getInitialProps = () => { const i18n = getI18n(); - const namespaces = i18n.reportNamespaces ? i18n.reportNamespaces.getUsedNamespaces() : []; + const namespaces = i18n.reportNamespaces?.getUsedNamespaces() ?? []; const ret = {}; const initialI18nStore = {}; diff --git a/src/useSSR.js b/src/useSSR.js index b3da6f82f..a1d44a83e 100644 --- a/src/useSSR.js +++ b/src/useSSR.js @@ -8,7 +8,7 @@ export const useSSR = (initialI18nStore, initialLanguage, props = {}) => { // opt out if is a cloned instance, eg. created by i18next-http-middleware on request // -> do not set initial stuff on server side - if (i18n.options && i18n.options.isClone) return; + if (i18n.options?.isClone) return; // nextjs / SSR: getting data from next.js or other ssr stack if (initialI18nStore && !i18n.initializedStoreOnce) { diff --git a/src/useTranslation.js b/src/useTranslation.js index e28581dd3..7b9b4426d 100644 --- a/src/useTranslation.js +++ b/src/useTranslation.js @@ -49,7 +49,7 @@ export const useTranslation = (ns, props = {}) => { return retNotReady; } - if (i18n.options.react && i18n.options.react.wait !== undefined) + if (i18n.options.react?.wait) warnOnce( 'It seems you are still using the old wait option, you may migrate to the new useSuspense behaviour.', ); @@ -58,11 +58,11 @@ export const useTranslation = (ns, props = {}) => { const { useSuspense, keyPrefix } = i18nOptions; // prepare having a namespace - let namespaces = ns || defaultNSFromContext || (i18n.options && i18n.options.defaultNS); + let namespaces = ns || defaultNSFromContext || i18n.options?.defaultNS; namespaces = isString(namespaces) ? [namespaces] : namespaces || ['translation']; // report namespaces as used - if (i18n.reportNamespaces.addUsedNamespaces) i18n.reportNamespaces.addUsedNamespaces(namespaces); + i18n.reportNamespaces.addUsedNamespaces?.(namespaces); // are we ready? yes if all namespaces in first language are loaded already (either with data or empty object on failed load) const ready = @@ -120,13 +120,13 @@ export const useTranslation = (ns, props = {}) => { }; // bind events to trigger change, like languageChanged - if (bindI18n && i18n) i18n.on(bindI18n, boundReset); - if (bindI18nStore && i18n) i18n.store.on(bindI18nStore, boundReset); + if (bindI18n) i18n?.on(bindI18n, boundReset); + if (bindI18nStore) i18n?.store.on(bindI18nStore, boundReset); // unbinding on unmount return () => { isMounted.current = false; - if (bindI18n && i18n) bindI18n.split(' ').forEach((e) => i18n.off(e, boundReset)); + if (i18n) bindI18n?.split(' ').forEach((e) => i18n.off(e, boundReset)); if (bindI18nStore && i18n) bindI18nStore.split(' ').forEach((e) => i18n.store.off(e, boundReset)); }; diff --git a/src/utils.js b/src/utils.js index 8c10aa5e5..26b3155bc 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,5 +1,5 @@ export const warn = (...args) => { - if (console && console.warn) { + if (console?.warn) { if (isString(args[0])) args[0] = `react-i18next:: ${args[0]}`; console.warn(...args); } @@ -54,7 +54,7 @@ export const loadLanguages = (i18n, lng, ns, cb) => { // WAIT A LITTLE FOR I18NEXT BEING UPDATED IN THE WILD, before removing this old i18next version support const oldI18nextHasLoadedNamespace = (ns, i18n, options = {}) => { const lng = i18n.languages[0]; - const fallbackLng = i18n.options ? i18n.options.fallbackLng : false; + const fallbackLng = i18n.options?.fallbackLng ?? false; const lastLng = i18n.languages[i18n.languages.length - 1]; // we're in cimode so this shall pass @@ -69,8 +69,7 @@ const oldI18nextHasLoadedNamespace = (ns, i18n, options = {}) => { // so set ready to false while we are changing the language // and namespace pending (depends on having a backend) if ( - options.bindI18n && - options.bindI18n.indexOf('languageChanging') > -1 && + options.bindI18n?.indexOf('languageChanging') > -1 && i18n.services.backendConnector.backend && i18n.isLanguageChangingTo && !loadNotPending(i18n.isLanguageChangingTo, ns) @@ -111,8 +110,7 @@ export const hasLoadedNamespace = (ns, i18n, options = {}) => { lng: options.lng, precheck: (i18nInstance, loadNotPending) => { if ( - options.bindI18n && - options.bindI18n.indexOf('languageChanging') > -1 && + options.bindI18n?.indexOf('languageChanging') > -1 && i18nInstance.services.backendConnector.backend && i18nInstance.isLanguageChangingTo && !loadNotPending(i18nInstance.isLanguageChangingTo, ns)