Skip to content

Commit

Permalink
feat: add codes and data to warnings to allow conditional logging
Browse files Browse the repository at this point in the history
  • Loading branch information
rawpixel-vincent committed Dec 29, 2024
1 parent ff509ba commit 8848b1e
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 33 deletions.
97 changes: 67 additions & 30 deletions src/TransWithoutContext.js
Original file line number Diff line number Diff line change
@@ -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';

Expand Down Expand Up @@ -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;
Expand All @@ -55,53 +58,77 @@ export const nodesToString = (children, i18nOptions, i18n, i18nKey) => {
// actual e.g. lorem <br/> ipsum
// expected e.g. lorem <br/> ipsum
stringNode += `<${type}/>`;
} else if (
(!childChildren && (!shouldKeepChild || childPropsCount)) ||
props.i18nIsDynamicList
) {
return;
}

if ((!childChildren && (!shouldKeepChild || childPropsCount)) || props.i18nIsDynamicList) {
// actual e.g. lorem <hr className="test" /> ipsum
// expected e.g. lorem <0></0> ipsum
// or
// we got a dynamic list like
// e.g. <ul i18nIsDynamicList>{['a', 'b'].map(item => ( <li key={item}>{item}</li> ))}</ul>
// expected e.g. "<0></0>", not e.g. "<0><0>a</0><1>b</1></0>"
stringNode += `<${childIndex}></${childIndex}>`;
} else if (shouldKeepChild && childPropsCount === 1 && isString(childChildren)) {
return;
}

if (shouldKeepChild && childPropsCount === 1 && isString(childChildren)) {
// actual e.g. dolor <strong>bold</strong> amet
// expected e.g. dolor <strong>bold</strong> 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);

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;
Expand Down Expand Up @@ -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
Expand All @@ -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, '<Trans /> component prop expects an object or an array');
warnOnce(i18n, `<Trans /> "components" prop expects an object or an array`, {
i18nKey,
code: ERR_CODES.TRANS_INVALID_COMPONENTS,
});
return null;
};

Expand All @@ -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;
}

Expand Down Expand Up @@ -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,
Expand Down
14 changes: 12 additions & 2 deletions src/useTranslation.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
hasLoadedNamespace,
isString,
isObject,
ERR_CODES,
} from './utils.js';

const usePrevious = (value, ignore) => {
Expand Down Expand Up @@ -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))
Expand All @@ -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 };
Expand Down
15 changes: 14 additions & 1 deletion src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down Expand Up @@ -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;
}

Expand Down

0 comments on commit 8848b1e

Please sign in to comment.