Skip to content

Commit 26616eb

Browse files
committed
use i18next logger if possible
Uses the i18next logger instead of the default console logger, if there is a valid i18next instance. Now the debug i18next option is respected, and you can also inject your own logger module: https://www.i18next.com/misc/creating-own-plugins#logger
1 parent 9b194b1 commit 26616eb

8 files changed

+92
-77
lines changed

CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
### 15.3.0
2+
3+
Uses the i18next logger instead of the default console logger, if there is a valid i18next instance. Now the debug i18next option is respected, and you can also inject your own logger module: https://www.i18next.com/misc/creating-own-plugins#logger
4+
15
### 15.2.0
26

37
This version may be breaking if you still use React < v18 with TypeScript.

example/react/package-lock.json

+26-33
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

example/react/package.json

+8-5
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@
33
"version": "0.1.0",
44
"private": true,
55
"dependencies": {
6-
"i18next": "^24.0.2",
7-
"i18next-browser-languagedetector": "^8.0.0",
6+
"i18next": "^24.2.0",
7+
"i18next-browser-languagedetector": "^8.0.2",
88
"i18next-http-backend": "^3.0.1",
9-
"react": "^18.3.1",
10-
"react-dom": "^18.3.1",
11-
"react-i18next": "^15.1.1",
9+
"react": "^19.0.0",
10+
"react-dom": "^19.0.0",
11+
"react-i18next": "^15.2.0",
1212
"react-scripts": "^5.0.1"
1313
},
14+
"overrides": {
15+
"typescript": "5.7.2"
16+
},
1417
"scripts": {
1518
"start": "react-scripts start",
1619
"build": "react-scripts build",

react-i18next.js

+27-22
Original file line numberDiff line numberDiff line change
@@ -118,23 +118,28 @@
118118
}
119119
};
120120

121-
const warn = function () {
122-
if (console?.warn) {
123-
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
124-
args[_key] = arguments[_key];
125-
}
121+
const warn = function (i18n) {
122+
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
123+
args[_key - 1] = arguments[_key];
124+
}
125+
if (i18n?.services?.logger?.forward) {
126+
i18n.services.logger.forward(args, 'warn', 'react-i18next::', true);
127+
} else if (i18n?.services?.logger?.warn) {
128+
if (isString(args[0])) args[0] = `react-i18next:: ${args[0]}`;
129+
i18n.services.logger.warn(...args);
130+
} else if (console?.warn) {
126131
if (isString(args[0])) args[0] = `react-i18next:: ${args[0]}`;
127132
console.warn(...args);
128133
}
129134
};
130135
const alreadyWarned = {};
131-
const warnOnce = function () {
132-
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
133-
args[_key2] = arguments[_key2];
136+
const warnOnce = function (i18n) {
137+
for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
138+
args[_key2 - 1] = arguments[_key2];
134139
}
135140
if (isString(args[0]) && alreadyWarned[args[0]]) return;
136141
if (isString(args[0])) alreadyWarned[args[0]] = new Date();
137-
warn(...args);
142+
warn(i18n, ...args);
138143
};
139144
const loadedClb = (i18n, cb) => () => {
140145
if (i18n.isInitialized) {
@@ -163,7 +168,7 @@
163168
const hasLoadedNamespace = function (ns, i18n) {
164169
let options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
165170
if (!i18n.languages || !i18n.languages.length) {
166-
warnOnce('i18n.languages were undefined or empty', i18n.languages);
171+
warnOnce(i18n, 'i18n.languages were undefined or empty', i18n.languages);
167172
return true;
168173
}
169174
return i18n.hasLoadedNamespace(ns, {
@@ -248,7 +253,7 @@
248253
newTarget.props = Object.assign(source.props, target.props);
249254
return newTarget;
250255
};
251-
const nodesToString = (children, i18nOptions) => {
256+
const nodesToString = (children, i18nOptions, i18n, i18nKey) => {
252257
if (!children) return '';
253258
let stringNode = '';
254259
const childrenArray = getAsArray(children);
@@ -271,11 +276,11 @@
271276
} else if (shouldKeepChild && childPropsCount === 1 && isString(childChildren)) {
272277
stringNode += `<${type}>${childChildren}</${type}>`;
273278
} else {
274-
const content = nodesToString(childChildren, i18nOptions);
279+
const content = nodesToString(childChildren, i18nOptions, i18n, i18nKey);
275280
stringNode += `<${childIndex}>${content}</${childIndex}>`;
276281
}
277282
} else if (child === null) {
278-
warn(`Trans: the passed in value is invalid - seems you passed in a null child.`);
283+
warn(i18n, `Trans: the passed in value is invalid - seems you passed in a null child.`);
279284
} else if (isObject(child)) {
280285
const {
281286
format,
@@ -286,10 +291,10 @@
286291
const value = format ? `${keys[0]}, ${format}` : keys[0];
287292
stringNode += `{{${value}}}`;
288293
} else {
289-
warn(`react-i18next: the passed in object contained more than one variable - the object should look like {{ value, format }} where format is optional.`, child);
294+
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);
290295
}
291296
} else {
292-
warn(`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);
297+
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);
293298
}
294299
});
295300
return stringNode;
@@ -433,15 +438,15 @@
433438
});
434439
return componentMap;
435440
};
436-
const generateComponents = (components, translation) => {
441+
const generateComponents = (components, translation, i18n) => {
437442
if (!components) return null;
438443
if (Array.isArray(components)) {
439444
return generateArrayComponents(components, translation);
440445
}
441446
if (isObject(components)) {
442447
return generateObjectComponents(components, translation);
443448
}
444-
warnOnce('<Trans /> component prop expects an object or an array');
449+
warnOnce(i18n, '<Trans /> component prop expects an object or an array');
445450
return null;
446451
};
447452
function Trans$1(_ref) {
@@ -463,7 +468,7 @@
463468
} = _ref;
464469
const i18n = i18nFromProps || getI18n();
465470
if (!i18n) {
466-
warnOnce('You will need to pass in an i18next instance by using i18nextReactModule');
471+
warnOnce(i18n, 'You will need to pass in an i18next instance by using i18nextReactModule');
467472
return children;
468473
}
469474
const t = tFromProps || i18n.t.bind(i18n) || (k => k);
@@ -473,7 +478,7 @@
473478
};
474479
let namespaces = ns || t.ns || i18n.options?.defaultNS;
475480
namespaces = isString(namespaces) ? [namespaces] : namespaces || ['translation'];
476-
const nodeAsString = nodesToString(children, reactI18nextOptions);
481+
const nodeAsString = nodesToString(children, reactI18nextOptions, i18n, i18nKey);
477482
const defaultValue = defaults || nodeAsString || reactI18nextOptions.transEmptyNodeValue || i18nKey;
478483
const {
479484
hashTransKey
@@ -504,7 +509,7 @@
504509
ns: namespaces
505510
};
506511
const translation = key ? t(key, combinedTOpts) : defaultValue;
507-
const generatedComponents = generateComponents(components, translation);
512+
const generatedComponents = generateComponents(components, translation, i18n);
508513
const content = renderNodes(generatedComponents || children, translation, i18n, reactI18nextOptions, combinedTOpts, shouldUnescape);
509514
const useAsParent = parent ?? reactI18nextOptions.defaultTransParent;
510515
return useAsParent ? react.createElement(useAsParent, additionalProps, content) : content;
@@ -618,7 +623,7 @@
618623
const i18n = i18nFromProps || i18nFromContext || getI18n();
619624
if (i18n && !i18n.reportNamespaces) i18n.reportNamespaces = new ReportNamespaces();
620625
if (!i18n) {
621-
warnOnce('You will need to pass in an i18next instance by using initReactI18next');
626+
warnOnce(i18n, 'You will need to pass in an i18next instance by using initReactI18next');
622627
const notReadyT = (k, optsOrDefaultValue) => {
623628
if (isString(optsOrDefaultValue)) return optsOrDefaultValue;
624629
if (isObject(optsOrDefaultValue) && isString(optsOrDefaultValue.defaultValue)) return optsOrDefaultValue.defaultValue;
@@ -630,7 +635,7 @@
630635
retNotReady.ready = false;
631636
return retNotReady;
632637
}
633-
if (i18n.options.react?.wait) warnOnce('It seems you are still using the old wait option, you may migrate to the new useSuspense behaviour.');
638+
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.');
634639
const i18nOptions = {
635640
...getDefaults(),
636641
...i18n.options.react,

0 commit comments

Comments
 (0)