1
1
import { Fragment , isValidElement , cloneElement , createElement , Children } from 'react' ;
2
2
import HTML from 'html-parse-stringify' ;
3
- import { isObject , isString , warn , warnOnce } from './utils.js' ;
3
+ import { ERR_CODES , isObject , isString , warnOnce } from './utils.js' ;
4
4
import { getDefaults } from './defaults.js' ;
5
5
import { getI18n } from './i18nInstance.js' ;
6
6
@@ -29,7 +29,7 @@ const mergeProps = (source, target) => {
29
29
return newTarget ;
30
30
} ;
31
31
32
- export const nodesToString = ( children , i18nOptions ) => {
32
+ export const nodesToString = ( children , i18nOptions , i18nKey , _parentWarnings ) => {
33
33
if ( ! children ) return '' ;
34
34
let stringNode = '' ;
35
35
@@ -39,6 +39,7 @@ export const nodesToString = (children, i18nOptions) => {
39
39
? ( i18nOptions . transKeepBasicHtmlNodesFor ?? [ ] )
40
40
: [ ] ;
41
41
42
+ const warnings = _parentWarnings || [ ] ;
42
43
// e.g. lorem <br/> ipsum {{ messageCount, format }} dolor <strong>bold</strong> amet
43
44
childrenArray . forEach ( ( child , childIndex ) => {
44
45
if ( isString ( child ) ) {
@@ -72,11 +73,14 @@ export const nodesToString = (children, i18nOptions) => {
72
73
stringNode += `<${ type } >${ childChildren } </${ type } >` ;
73
74
} else {
74
75
// regular case mapping the inner children
75
- const content = nodesToString ( childChildren , i18nOptions ) ;
76
+ const content = nodesToString ( childChildren , i18nOptions , i18nKey , warnings ) ;
76
77
stringNode += `<${ childIndex } >${ content } </${ childIndex } >` ;
77
78
}
78
79
} else if ( child === null ) {
79
- warn ( `Trans: the passed in value is invalid - seems you passed in a null child.` ) ;
80
+ warnings . push ( {
81
+ code : ERR_CODES . TRANS_NULL_VALUE ,
82
+ message : `The passed in value is invalid - seems you passed in a null child.` ,
83
+ } ) ;
80
84
} else if ( isObject ( child ) ) {
81
85
// e.g. lorem {{ value, format }} ipsum
82
86
const { format, ...clone } = child ;
@@ -87,19 +91,28 @@ export const nodesToString = (children, i18nOptions) => {
87
91
stringNode += `{{${ value } }}` ;
88
92
} else {
89
93
// not a valid interpolation object (can only contain one value plus format)
90
- warn (
91
- `react-i18next: the passed in object contained more than one variable - the object should look like {{ value, format }} where format is optional.` ,
94
+ warnings . push ( {
95
+ code : ERR_CODES . TRANS_INVALID_OBJ ,
96
+ message : `The passed in object contained more than one variable - the object should look like {{ value, format }} where format is optional.` ,
92
97
child,
93
- ) ;
98
+ } ) ;
94
99
}
95
100
} else {
96
- warn (
97
- `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}}.` ,
101
+ warnings . push ( {
102
+ code : ERR_CODES . TRANS_INVALID_VAR ,
103
+ message : `Passed in a variable like {number} - please pass in variables for interpolation as full objects like {{number}}.` ,
98
104
child,
99
- ) ;
105
+ } ) ;
100
106
}
101
107
} ) ;
102
108
109
+ if ( warnings . length && ! _parentWarnings ) {
110
+ warnOnce ( `Trans:key:${ i18nKey } : Interpolation errors - check the passed childrens.` , {
111
+ i18nKey,
112
+ warnings,
113
+ } ) ;
114
+ }
115
+
103
116
return stringNode ;
104
117
} ;
105
118
@@ -332,7 +345,7 @@ const generateObjectComponents = (components, translation) => {
332
345
return componentMap ;
333
346
} ;
334
347
335
- const generateComponents = ( components , translation ) => {
348
+ const generateComponents = ( components , translation , i18nKey ) => {
336
349
if ( ! components ) return null ;
337
350
338
351
// components could be either an array or an object
@@ -347,7 +360,15 @@ const generateComponents = (components, translation) => {
347
360
348
361
// if components is not an array or an object, warn the user
349
362
// and return null
350
- warnOnce ( '<Trans /> component prop expects an object or an array' ) ;
363
+ warnOnce ( `Trans:key:${ i18nKey } "components" prop expects an object or an array` , {
364
+ i18nKey,
365
+ warnings : [
366
+ {
367
+ code : ERR_CODES . TRANS_INVALID_COMPONENTS ,
368
+ message : `<Trans /> "components" prop expects an object or an array, received ${ typeof components } ` ,
369
+ } ,
370
+ ] ,
371
+ } ) ;
351
372
return null ;
352
373
} ;
353
374
@@ -370,7 +391,15 @@ export function Trans({
370
391
const i18n = i18nFromProps || getI18n ( ) ;
371
392
372
393
if ( ! i18n ) {
373
- warnOnce ( 'You will need to pass in an i18next instance by using i18nextReactModule' ) ;
394
+ warnOnce ( 'Trans: You will need to pass in an i18next instance by using i18nextReactModule' , {
395
+ i18nKey,
396
+ warnings : [
397
+ {
398
+ code : ERR_CODES . NO_I18NEXT_INSTANCE ,
399
+ message : 'You will need to pass in an i18next instance by using i18nextReactModule' ,
400
+ } ,
401
+ ] ,
402
+ } ) ;
374
403
return children ;
375
404
}
376
405
@@ -382,7 +411,7 @@ export function Trans({
382
411
let namespaces = ns || t . ns || i18n . options ?. defaultNS ;
383
412
namespaces = isString ( namespaces ) ? [ namespaces ] : namespaces || [ 'translation' ] ;
384
413
385
- const nodeAsString = nodesToString ( children , reactI18nextOptions ) ;
414
+ const nodeAsString = nodesToString ( children , reactI18nextOptions , i18nKey ) ;
386
415
const defaultValue =
387
416
defaults || nodeAsString || reactI18nextOptions . transEmptyNodeValue || i18nKey ;
388
417
const { hashTransKey } = reactI18nextOptions ;
@@ -413,7 +442,7 @@ export function Trans({
413
442
} ;
414
443
const translation = key ? t ( key , combinedTOpts ) : defaultValue ;
415
444
416
- const generatedComponents = generateComponents ( components , translation ) ;
445
+ const generatedComponents = generateComponents ( components , translation , i18nKey ) ;
417
446
418
447
const content = renderNodes (
419
448
generatedComponents || children ,
0 commit comments