diff --git a/.eslintrc b/.eslintrc index fef49bba..ac055f37 100644 --- a/.eslintrc +++ b/.eslintrc @@ -93,6 +93,7 @@ { "aspects": ["invalidHref"] } - ] + ], + "react/jsx-props-no-spreading": 0 } } diff --git a/package.json b/package.json index eb898df4..df20dfa8 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "@types/react": "^16.8.2", "all-contributors-cli": "^6.1.1", "babel-core": "^7.0.0-bridge.0", - "babel-eslint": "10.0.2", + "babel-eslint": "10.0.3", "babel-jest": "24.8.0", "babel-plugin-macros": "^2.5.0", "babel-plugin-tester": "^6.0.0", @@ -51,12 +51,12 @@ "enzyme": "^3.8.0", "enzyme-adapter-react-16": "^1.9.1", "enzyme-adapter-react-helper": "^1.3.2", - "eslint": "6.1.0", - "eslint-config-airbnb": "18.0.0", - "eslint-config-prettier": "6.0.0", + "eslint": "6.5.1", + "eslint-config-airbnb": "18.0.1", + "eslint-config-prettier": "6.4.0", "eslint-plugin-import": "2.18.2", "eslint-plugin-jsx-a11y": "6.2.3", - "eslint-plugin-react": "7.14.3", + "eslint-plugin-react": "7.16.0", "husky": "^3.0.3", "i18next": "^17.0.8", "jest": "24.8.0", @@ -99,7 +99,7 @@ "test:watch": "cross-env BABEL_ENV=development jest --no-cache --watch", "test:coverage": "cross-env BABEL_ENV=development jest --no-cache --coverage", "test:coverageOldEnzymeAdapter": "enzyme-adapter-react-install 16 && cross-env BABEL_ENV=development jest --no-cache --coverage", - "test:lint": "./node_modules/.bin/eslint ./src", + "test:lint": "eslint ./src ./test", "test:typescript": "tslint --project tsconfig.json", "test:typescript:noninterop": "tslint --project tsconfig.nonEsModuleInterop.json", "contributors:add": "all-contributors add", diff --git a/src/Trans.js b/src/Trans.js index aad23152..439d1989 100644 --- a/src/Trans.js +++ b/src/Trans.js @@ -17,18 +17,22 @@ function hasValidReactChildren(children) { return children.every(child => React.isValidElement(child)); } -export function nodesToString(mem, children, index, i18nOptions) { +function getAsArray(data) { + return Array.isArray(data) ? data : [data]; +} + +export function nodesToString(startingString, children, index, i18nOptions) { if (!children) return ''; - if (Object.prototype.toString.call(children) !== '[object Array]') children = [children]; + let stringNode = startingString; + + const childrenArray = getAsArray(children); const keepArray = i18nOptions.transKeepBasicHtmlNodesFor || []; - children.forEach((child, i) => { - // const isElement = React.isValidElement(child); - // const elementKey = `${index !== 0 ? index + '-' : ''}${i}:${typeof child.type === 'function' ? child.type.name : child.type || 'var'}`; + childrenArray.forEach((child, i) => { const elementKey = `${i}`; if (typeof child === 'string') { - mem = `${mem}${child}`; + stringNode = `${stringNode}${child}`; } else if (hasChildren(child)) { const elementTag = keepArray.indexOf(child.type) > -1 && @@ -40,10 +44,10 @@ export function nodesToString(mem, children, index, i18nOptions) { if (child.props && child.props.i18nIsDynamicList) { // we got a dynamic list like """ // the result should be "<0>" and not "<0><0>a<1>b" - mem = `${mem}<${elementTag}>`; + stringNode = `${stringNode}<${elementTag}>`; } else { // regular case mapping the inner children - mem = `${mem}<${elementTag}>${nodesToString( + stringNode = `${stringNode}<${elementTag}>${nodesToString( '', getChildren(child), i + 1, @@ -52,9 +56,9 @@ export function nodesToString(mem, children, index, i18nOptions) { } } else if (React.isValidElement(child)) { if (keepArray.indexOf(child.type) > -1 && Object.keys(child.props).length === 0) { - mem = `${mem}<${child.type}/>`; + stringNode = `${stringNode}<${child.type}/>`; } else { - mem = `${mem}<${elementKey}>`; + stringNode = `${stringNode}<${elementKey}>`; } } else if (typeof child === 'object') { const clone = { ...child }; @@ -63,9 +67,9 @@ export function nodesToString(mem, children, index, i18nOptions) { const keys = Object.keys(clone); if (format && keys.length === 1) { - mem = `${mem}{{${keys[0]}, ${format}}}`; + stringNode = `${stringNode}{{${keys[0]}, ${format}}}`; } else if (keys.length === 1) { - mem = `${mem}{{${keys[0]}}}`; + stringNode = `${stringNode}{{${keys[0]}}}`; } else { // not a valid interpolation object (can only contain one value plus format) warn( @@ -81,7 +85,7 @@ export function nodesToString(mem, children, index, i18nOptions) { } }); - return mem; + return stringNode; } function renderNodes(children, targetString, i18n, i18nOptions, combinedTOpts) { @@ -97,17 +101,21 @@ function renderNodes(children, targetString, i18n, i18nOptions, combinedTOpts) { // v2 -> interpolates upfront no need for "some <0>{{var}}"" -> will be just "some {{var}}" in translation file const data = {}; + function getData(childs) { - if (Object.prototype.toString.call(childs) !== '[object Array]') childs = [childs]; - childs.forEach(child => { + const childrenArray = getAsArray(childs); + + childrenArray.forEach(child => { if (typeof child === 'string') return; if (hasChildren(child)) getData(getChildren(child)); else if (typeof child === 'object' && !React.isValidElement(child)) Object.assign(data, child); }); } + getData(children); - targetString = i18n.services.interpolator.interpolate( + + const interpolatedString = i18n.services.interpolator.interpolate( targetString, { ...data, ...combinedTOpts }, i18n.language, @@ -115,11 +123,11 @@ function renderNodes(children, targetString, i18n, i18nOptions, combinedTOpts) { // parse ast from string with additional wrapper tag // -> avoids issues in parser removing prepending text nodes - const ast = HTML.parse(`<0>${targetString}`); + const ast = HTML.parse(`<0>${interpolatedString}`); - function mapAST(reactNodes, astNodes) { - if (Object.prototype.toString.call(reactNodes) !== '[object Array]') reactNodes = [reactNodes]; - if (Object.prototype.toString.call(astNodes) !== '[object Array]') astNodes = [astNodes]; + function mapAST(reactNode, astNode) { + const reactNodes = getAsArray(reactNode); + const astNodes = getAsArray(astNode); return astNodes.reduce((mem, node, i) => { const translationContent = node.children && node.children[0] && node.children[0].content; @@ -148,7 +156,7 @@ function renderNodes(children, targetString, i18n, i18nOptions, combinedTOpts) { // so we just need to map the inner stuff const inner = mapAST(reactNodes /* wrong but we need something */, node.children); mem.push(React.cloneElement(child, { ...child.props, key: i }, inner)); - } else if (isNaN(node.name)) { + } else if (Number.isNaN(parseFloat(node.name))) { if (i18nOptions.transSupportBasicHtmlNodes && keepArray.indexOf(node.name) > -1) { if (node.voidElement) { mem.push(React.createElement(node.name, { key: `${node.name}-${i}` })); diff --git a/src/Translation.js b/src/Translation.js index 15677425..c4547347 100644 --- a/src/Translation.js +++ b/src/Translation.js @@ -1,4 +1,3 @@ -import React from 'react'; import { useTranslation } from './useTranslation'; export function Translation(props) { diff --git a/src/withTranslation.js b/src/withTranslation.js index bc46c0c4..67458f6b 100644 --- a/src/withTranslation.js +++ b/src/withTranslation.js @@ -25,8 +25,8 @@ export function withTranslation(ns, options = {}) { I18nextWithTranslation.WrappedComponent = WrappedComponent; - return options.withRef - ? React.forwardRef((props, ref) => ) - : I18nextWithTranslation; + const forwardRef = (props, ref) => ; + + return options.withRef ? React.forwardRef(forwardRef) : I18nextWithTranslation; }; } diff --git a/test/Translation.spec.js b/test/Translation.spec.js index 36cf0015..7c89e97b 100644 --- a/test/Translation.spec.js +++ b/test/Translation.spec.js @@ -1,6 +1,6 @@ import React from 'react'; import { mount } from 'enzyme'; -import i18n from './i18n'; +import './i18n'; import { Translation } from '../src/Translation'; jest.unmock('../src/Translation'); diff --git a/test/i18n.js b/test/i18n.js index 1d0bdd25..264a06e1 100644 --- a/test/i18n.js +++ b/test/i18n.js @@ -49,7 +49,7 @@ i18n.init({ interpolation: { escapeValue: false, // not needed for react!! formatSeparator: ',', - format(value, format, lng) { + format(value, format) { if (format === 'uppercase') return value.toUpperCase(); return value; }, diff --git a/test/trans.nodeToString.spec.js b/test/trans.nodeToString.spec.js index c8df68e0..7b6e6c6d 100644 --- a/test/trans.nodeToString.spec.js +++ b/test/trans.nodeToString.spec.js @@ -1,4 +1,3 @@ -import React from 'react'; import { nodesToString } from '../src/Trans'; describe('trans nodeToString', () => { diff --git a/test/trans.render.spec.js b/test/trans.render.spec.js index 2b380dde..d2db8dda 100644 --- a/test/trans.render.spec.js +++ b/test/trans.render.spec.js @@ -1,6 +1,5 @@ import React from 'react'; -import { shallow, render, mount } from 'enzyme'; -import ifReact from 'enzyme-adapter-react-helper/build/ifReact'; +import { mount } from 'enzyme'; import i18n from './i18n'; import { withTranslation } from '../src/withTranslation'; import { Trans } from '../src/Trans'; @@ -10,15 +9,11 @@ function Link({ to, children }) { } describe('trans simple', () => { - const TestElement = ({ t, parent }) => { - const count = 10; - const name = 'Jan'; - return ( - - Open here. - - ); - }; + const TestElement = ({ parent }) => ( + + Open here. + + ); it('should render correct content', () => { const wrapper = mount(); @@ -76,7 +71,7 @@ describe('trans simple', () => { }); describe('trans simple using ns prop', () => { - const TestElement = ({ t, parent }) => ( + const TestElement = ({ parent }) => ( Open here. @@ -96,19 +91,15 @@ describe('trans simple using ns prop', () => { }); describe('trans simple with custom html tag', () => { - const TestElement = ({ t, parent }) => ( + const TestElement = ({ parent }) => ( Open here. ); - const TestElement2 = ({ t, parent }) => ( - - ); + const TestElement2 = ({ parent }) => ; - const TestElement3 = ({ t, parent }) => ( - - ); + const TestElement3 = ({ parent }) => ; it('should not skip custom html tags', () => { const wrapper = mount(); @@ -150,7 +141,7 @@ describe('trans simple with custom html tag', () => { }); describe('trans testTransKey1 singular', () => { - const TestElement = ({ t }) => { + const TestElement = () => { const numOfItems = 1; return ( @@ -167,7 +158,7 @@ describe('trans testTransKey1 singular', () => { }); describe('trans testTransKey1 plural', () => { - const TestElement = ({ t }) => { + const TestElement = () => { const numOfItems = 10; return ( @@ -184,7 +175,7 @@ describe('trans testTransKey1 plural', () => { }); describe('trans testTransKey2', () => { - const TestElement = ({ t }) => { + const TestElement = () => { const numOfItems = 10; return ( @@ -207,7 +198,7 @@ describe('trans testTransKey2', () => { }); describe('trans testTransKey3', () => { - const TestElement = ({ t }) => { + const TestElement = () => { const numOfItems = 10; return ( @@ -230,7 +221,7 @@ describe('trans testTransKey3', () => { }); describe('trans complex', () => { - const TestElement = ({ t }) => { + const TestElement = () => { const count = 10; const name = 'Jan'; // prettier-ignore @@ -255,7 +246,7 @@ describe('trans complex', () => { }); describe('trans complex - count only in props', () => { - const TestElement = ({ t }) => { + const TestElement = () => { const count = 10; const name = 'Jan'; // prettier-ignore @@ -280,7 +271,7 @@ describe('trans complex - count only in props', () => { }); describe('trans complex v2 no extra pseudo elements for interpolation', () => { - const TestElement = ({ t }) => { + const TestElement = () => { const count = 10; const name = 'Jan'; // prettier-ignore diff --git a/test/useTranslation.usedNamespaces.spec.js b/test/useTranslation.usedNamespaces.spec.js index a5adde97..27430e01 100644 --- a/test/useTranslation.usedNamespaces.spec.js +++ b/test/useTranslation.usedNamespaces.spec.js @@ -30,7 +30,7 @@ describe('useTranslation', () => { } it('should render correct content if ready (having all ns)', () => { - const wrapper = mount(, {}); + mount(, {}); // console.log(wrapper.debug()); expect(i18n.reportNamespaces.getUsedNamespaces()).toEqual(['ns1', 'ns2', 'ns3']); }); diff --git a/test/withSSR.spec.js b/test/withSSR.spec.js index 2523a6f4..c9797133 100644 --- a/test/withSSR.spec.js +++ b/test/withSSR.spec.js @@ -33,11 +33,11 @@ const mockI18n = { describe('withSSR', () => { function TestComponent() { - const { t } = useTranslation('ns1'); + useTranslation('ns1'); return
SSR
; } - TestComponent.getInitialProps = async ctx => ({ foo: 'bar' }); + TestComponent.getInitialProps = async () => ({ foo: 'bar' }); beforeAll(() => { setI18n(mockI18n); diff --git a/test/withTranslation.spec.js b/test/withTranslation.spec.js index e70da4db..ab93956e 100644 --- a/test/withTranslation.spec.js +++ b/test/withTranslation.spec.js @@ -31,7 +31,7 @@ describe('withTranslation', () => { it('should has ref', () => { const HocElement = withTranslation('translation', { withRef: true })(TestComponent); const hocRef = React.createRef(); - const parentWrapper = mount(); + mount(); expect(hocRef.current).not.toBeNull(); }); });