diff --git a/src/TransWithoutContext.js b/src/TransWithoutContext.js
index f47a99ef..801196c7 100644
--- a/src/TransWithoutContext.js
+++ b/src/TransWithoutContext.js
@@ -1,6 +1,6 @@
import { Fragment, isValidElement, cloneElement, createElement, Children } from 'react';
import HTML from 'html-parse-stringify';
-import { isObject, isString, warn, warnOnce } from './utils.js';
+import { ERR_CODES, isObject, isString, warn, warnOnce } from './utils.js';
import { getDefaults } from './defaults.js';
import { getI18n } from './i18nInstance.js';
@@ -45,7 +45,10 @@ export const nodesToString = (children, i18nOptions, i18n, i18nKey) => {
// actual e.g. lorem
// expected e.g. lorem
stringNode += `${child}`;
- } else if (isValidElement(child)) {
+ return;
+ }
+
+ if (isValidElement(child)) {
const { props, type } = child;
const childPropsCount = Object.keys(props).length;
const shouldKeepChild = keepArray.indexOf(type) > -1;
@@ -55,10 +58,10 @@ export const nodesToString = (children, i18nOptions, i18n, i18nKey) => {
// actual e.g. lorem
ipsum
// expected e.g. lorem
ipsum
stringNode += `<${type}/>`;
- } else if (
- (!childChildren && (!shouldKeepChild || childPropsCount)) ||
- props.i18nIsDynamicList
- ) {
+ return;
+ }
+
+ if ((!childChildren && (!shouldKeepChild || childPropsCount)) || props.i18nIsDynamicList) {
// actual e.g. lorem
ipsum
// expected e.g. lorem <0>0> ipsum
// or
@@ -66,18 +69,32 @@ export const nodesToString = (children, i18nOptions, i18n, i18nKey) => {
// e.g. {['a', 'b'].map(item => ( - {item}
))}
// expected e.g. "<0>0>", not e.g. "<0><0>a0><1>b1>0>"
stringNode += `<${childIndex}>${childIndex}>`;
- } else if (shouldKeepChild && childPropsCount === 1 && isString(childChildren)) {
+ return;
+ }
+
+ if (shouldKeepChild && childPropsCount === 1 && isString(childChildren)) {
// actual e.g. dolor bold amet
// expected e.g. dolor bold amet
stringNode += `<${type}>${childChildren}${type}>`;
- } else {
- // regular case mapping the inner children
- const content = nodesToString(childChildren, i18nOptions, i18n, i18nKey);
- stringNode += `<${childIndex}>${content}${childIndex}>`;
+ return;
}
- } else if (child === null) {
- warn(i18n, `Trans: the passed in value is invalid - seems you passed in a null child.`);
- } else if (isObject(child)) {
+
+ // regular case mapping the inner children
+ const content = nodesToString(childChildren, i18nOptions, i18n, i18nKey);
+ stringNode += `<${childIndex}>${content}${childIndex}>`;
+
+ return;
+ }
+
+ if (child === null) {
+ warn(i18n, `Trans: The passed in value is invalid - seems you passed in a null child.`, {
+ code: ERR_CODES.TRANS_NULL_VALUE,
+ i18nKey,
+ });
+ return;
+ }
+
+ if (isObject(child)) {
// e.g. lorem {{ value, format }} ipsum
const { format, ...clone } = child;
const keys = Object.keys(clone);
@@ -85,23 +102,33 @@ export const nodesToString = (children, i18nOptions, i18n, i18nKey) => {
if (keys.length === 1) {
const value = format ? `${keys[0]}, ${format}` : keys[0];
stringNode += `{{${value}}}`;
- } else {
- // not a valid interpolation object (can only contain one value plus format)
- warn(
- i18n,
- `react-i18next: the passed in object contained more than one variable - the object should look like {{ value, format }} where format is optional.`,
- child,
- i18nKey,
- );
+ return;
}
- } else {
+
+ // not a valid interpolation object (can only contain one value plus format)
warn(
i18n,
- `Trans: the passed in value is invalid - seems you passed in a variable like {number} - please pass in variables for interpolation as full objects like {{number}}.`,
- child,
- i18nKey,
+ `Trans: The passed in object contained more than one variable - the object should look like {{ value, format }} where format is optional.`,
+ {
+ code: ERR_CODES.TRANS_INVALID_OBJ,
+ i18nKey,
+ child,
+ },
);
+
+ return;
}
+
+ // e.g. lorem {number} ipsum
+ warn(
+ i18n,
+ `Trans: Passed in a variable like {number} - please pass in variables for interpolation as full objects like {{number}}.`,
+ {
+ code: ERR_CODES.TRANS_INVALID_VAR,
+ i18nKey,
+ child,
+ },
+ );
});
return stringNode;
@@ -336,7 +363,7 @@ const generateObjectComponents = (components, translation) => {
return componentMap;
};
-const generateComponents = (components, translation, i18n) => {
+const generateComponents = (components, translation, i18n, i18nKey) => {
if (!components) return null;
// components could be either an array or an object
@@ -351,7 +378,10 @@ const generateComponents = (components, translation, i18n) => {
// if components is not an array or an object, warn the user
// and return null
- warnOnce(i18n, ' component prop expects an object or an array');
+ warnOnce(i18n, ` "components" prop expects an object or an array`, {
+ i18nKey,
+ code: ERR_CODES.TRANS_INVALID_COMPONENTS,
+ });
return null;
};
@@ -374,7 +404,14 @@ export function Trans({
const i18n = i18nFromProps || getI18n();
if (!i18n) {
- warnOnce(i18n, 'You will need to pass in an i18next instance by using i18nextReactModule');
+ warnOnce(
+ i18n,
+ 'Trans: You will need to pass in an i18next instance by using i18nextReactModule',
+ {
+ i18nKey,
+ code: ERR_CODES.NO_I18NEXT_INSTANCE,
+ },
+ );
return children;
}
@@ -417,7 +454,7 @@ export function Trans({
};
const translation = key ? t(key, combinedTOpts) : defaultValue;
- const generatedComponents = generateComponents(components, translation, i18n);
+ const generatedComponents = generateComponents(components, translation, i18n, i18nKey);
const content = renderNodes(
generatedComponents || children,
diff --git a/src/useTranslation.js b/src/useTranslation.js
index 8241e1c2..fcdf8320 100644
--- a/src/useTranslation.js
+++ b/src/useTranslation.js
@@ -7,6 +7,7 @@ import {
hasLoadedNamespace,
isString,
isObject,
+ ERR_CODES,
} from './utils.js';
const usePrevious = (value, ignore) => {
@@ -35,7 +36,13 @@ export const useTranslation = (ns, props = {}) => {
const i18n = i18nFromProps || i18nFromContext || getI18n();
if (i18n && !i18n.reportNamespaces) i18n.reportNamespaces = new ReportNamespaces();
if (!i18n) {
- warnOnce(i18n, 'You will need to pass in an i18next instance by using initReactI18next');
+ warnOnce(
+ i18n,
+ 'useTranslation: You will need to pass in an i18next instance by using initReactI18next',
+ {
+ code: ERR_CODES.NO_I18NEXT_INSTANCE,
+ },
+ );
const notReadyT = (k, optsOrDefaultValue) => {
if (isString(optsOrDefaultValue)) return optsOrDefaultValue;
if (isObject(optsOrDefaultValue) && isString(optsOrDefaultValue.defaultValue))
@@ -52,7 +59,10 @@ export const useTranslation = (ns, props = {}) => {
if (i18n.options.react?.wait)
warnOnce(
i18n,
- 'It seems you are still using the old wait option, you may migrate to the new useSuspense behaviour.',
+ 'useTranslation: It seems you are still using the old wait option, you may migrate to the new useSuspense behaviour.',
+ {
+ code: ERR_CODES.DEPRECATED_WAIT_OPTION,
+ },
);
const i18nOptions = { ...getDefaults(), ...i18n.options.react, ...props };
diff --git a/src/utils.js b/src/utils.js
index 0c96bd8f..7e6e3d8e 100644
--- a/src/utils.js
+++ b/src/utils.js
@@ -17,6 +17,16 @@ export const warnOnce = (i18n, ...args) => {
warn(i18n, ...args);
};
+export const ERR_CODES = {
+ NO_I18NEXT_INSTANCE: 'NO_I18NEXT_INSTANCE',
+ DEPRECATED_WAIT_OPTION: 'DEPRECATED_WAIT_OPTION',
+ TRANS_NULL_VALUE: 'TRANS_NULL_VALUE',
+ TRANS_INVALID_OBJ: 'TRANS_INVALID_OBJ',
+ TRANS_INVALID_VAR: 'TRANS_INVALID_VAR',
+ TRANS_INVALID_COMPONENTS: 'TRANS_INVALID_COMPONENTS',
+ MISSING_LANGUAGES: 'MISSING_LANGUAGES',
+};
+
// not needed right now
//
// export const deprecated = (i18n, ...args) => {
@@ -60,7 +70,10 @@ export const loadLanguages = (i18n, lng, ns, cb) => {
export const hasLoadedNamespace = (ns, i18n, options = {}) => {
if (!i18n.languages || !i18n.languages.length) {
- warnOnce(i18n, 'i18n.languages were undefined or empty', i18n.languages);
+ warnOnce(i18n, 'i18n.languages were undefined or empty', {
+ code: ERR_CODES.MISSING_LANGUAGES,
+ languages: i18n.languages,
+ });
return true;
}