Skip to content

Commit 0884521

Browse files
feat(parser): Handle a few more use cases of potential count attributes.
1 parent 40e23c6 commit 0884521

File tree

3 files changed

+129
-5
lines changed

3 files changed

+129
-5
lines changed

src/parser.js

+22
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,28 @@ class Parser {
614614
}, {});
615615
}
616616

617+
// Member Expression (e.g. i18nKey={foo.bar})
618+
if (expression.type === 'MemberExpression') {
619+
acc[name] = expression.object.name + '.' + expression.property.name;
620+
}
621+
622+
// Conditional Expression (e.g. i18nKey={true ? 'foo' : 'bar'})
623+
if (expression.type === 'ConditionalExpression') {
624+
acc[name] = expression.consequent.value;
625+
}
626+
627+
// Unary Expression (e.g. i18nKey={foo?.bar})
628+
if (expression.type === 'UnaryExpression') {
629+
acc[name] = expression.alternate.object.name + '.' + expression.alternate.property.name;
630+
}
631+
632+
// Binary Expression (e.g. i18nKey={foo.bar - 1})
633+
if (expression.type === 'BinaryExpression') {
634+
if (expression.left.type === 'MemberExpression' && expression.right.type === 'Literal') {
635+
acc[name] = expression.left.object.name + '.' + expression.left.property.name;
636+
}
637+
}
638+
617639
// Template Literal
618640
if (expression.type === 'TemplateLiteral') {
619641
acc[name] = expression.quasis

test/react-i18next/i18n.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ i18n.init({
2828
transTest2InV2: 'Hello <1>{{name}}</1>, you have {{count}} message. Open <5>hear</5>.',
2929
transTest2InV2_other:
3030
'Hello <1>{{name}}</1>, you have {{count}} messages. Open <5>here</5>.',
31+
transPluralWithCountAsMemberExpression: '{{count}} item',
32+
transPluralWithCountAsMemberExpression_other: '{{count}} items',
3133
testTransKey1: '<0>{{numOfItems}}</0> item matched.',
3234
testTransKey1_other: '<0>{{numOfItems}}</0> items matched.',
3335
testTransKey2: '<0><0>{{numOfItems}}</0></0> item matched.',
@@ -53,7 +55,9 @@ i18n.init({
5355
escapeValue: false, // not needed for react!!
5456
formatSeparator: ',',
5557
format(value, format) {
56-
if (format === 'uppercase') return value.toUpperCase();
58+
if (format === 'uppercase') {
59+
return value.toUpperCase();
60+
}
5761
return value;
5862
},
5963
},

test/react-i18next/trans-render.test.js

+102-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/** @jest-environment jsdom */
2-
import React from 'react';
32
import { render } from '@testing-library/react';
3+
import React from 'react';
44
import {
55
Trans,
66
withTranslation,
@@ -309,7 +309,7 @@ describe('trans complex - count only in props', () => {
309309
// prettier-ignore
310310
return (
311311
<Trans i18nKey="transTest2" count={count}>
312-
Hello <strong>{{ name }}</strong>, you have {{n: count}} message. Open <Link to="/msgs">here</Link>.
312+
Hello <strong>{{ name }}</strong>, you have {{ n: count }} message. Open <Link to="/msgs">here</Link>.
313313
</Trans>
314314
);
315315
};
@@ -368,10 +368,108 @@ describe('trans complex v2 no extra pseudo elements for interpolation', () => {
368368
});
369369
});
370370

371+
describe('Trans with a count using an object property should be detected as a translation with a plural', () => {
372+
const TestComponent = () => {
373+
const obj = { anyProp: { a: 10 } };
374+
// prettier-ignore
375+
return (
376+
<Trans
377+
i18nKey="transPluralWithCountAsMemberExpression"
378+
count={obj.anyProp.a}
379+
>
380+
{{ count: obj.anyProp }} item.
381+
</Trans>
382+
);
383+
};
384+
385+
it('should render correct content with the count', () => {
386+
const { container } = render(<TestComponent />);
387+
expect(container.firstChild).toMatchInlineSnapshot(`
388+
<div>
389+
10 items
390+
</div>
391+
`);
392+
});
393+
});
394+
395+
describe('Trans with a count using an conditionnal statement should be detected as a translation with a plural', () => {
396+
const TestComponent = () => {
397+
const obj = true;
398+
// prettier-ignore
399+
return (
400+
<Trans
401+
i18nKey="transPluralWithCountAsMemberExpression"
402+
count={obj ? 3 : 10}
403+
>
404+
{{ count: 6 }} item.
405+
</Trans>
406+
);
407+
};
408+
409+
it('should render correct content with the count', () => {
410+
const { container } = render(<TestComponent />);
411+
expect(container.firstChild).toMatchInlineSnapshot(`
412+
<div>
413+
3 items
414+
</div>
415+
`);
416+
});
417+
});
418+
419+
describe('Trans with a count using an Unary Expression statement should be detected as a translation with a plural', () => {
420+
const TestComponent = () => {
421+
const obj = { a: 3 };
422+
// prettier-ignore
423+
return (
424+
<Trans
425+
i18nKey="transPluralWithCountAsMemberExpression"
426+
count={obj?.a}
427+
>
428+
{{ count: 6 }} item.
429+
</Trans>
430+
);
431+
};
432+
433+
it('should render correct content with the count', () => {
434+
const { container } = render(<TestComponent />);
435+
expect(container.firstChild).toMatchInlineSnapshot(`
436+
<div>
437+
3 items
438+
</div>
439+
`);
440+
});
441+
});
442+
443+
describe('Trans with a count using an Binary Expression statement should be detected as a translation with a plural', () => {
444+
const TestComponent = () => {
445+
const obj = { a: 3 };
446+
// prettier-ignore
447+
return (
448+
<Trans
449+
i18nKey="transPluralWithCountAsMemberExpression"
450+
count={obj.a - 1}
451+
>
452+
{{ count: 6 }} item.
453+
</Trans>
454+
);
455+
};
456+
457+
it('should render correct content with the count', () => {
458+
const { container } = render(<TestComponent />);
459+
expect(container.firstChild).toMatchInlineSnapshot(`
460+
<div>
461+
2 items
462+
</div>
463+
`);
464+
});
465+
});
466+
371467
describe('trans with t as prop', () => {
372468
const TestComponent = ({ t, cb }) => {
373469
const customT = (...args) => {
374-
if (cb) cb();
470+
if (cb) {
471+
cb();
472+
}
375473
return t(...args);
376474
};
377475
return (
@@ -415,7 +513,7 @@ describe('trans with empty content', () => {
415513
const TestComponent = () => <Trans />;
416514
it('should render an empty string', () => {
417515
const { container } = render(<TestComponent />);
418-
expect(container.firstChild).toMatchInlineSnapshot(`<div />`);
516+
expect(container.firstChild).toMatchInlineSnapshot('<div />');
419517
});
420518
});
421519

0 commit comments

Comments
 (0)