diff --git a/awx/ui_next/.eslintrc b/awx/ui_next/.eslintrc index e2bf9305bd..c93c2a8992 100644 --- a/awx/ui_next/.eslintrc +++ b/awx/ui_next/.eslintrc @@ -8,8 +8,8 @@ "modules": true } }, - "plugins": ["react-hooks", "jsx-a11y"], - "extends": ["airbnb", "prettier", "prettier/react", "plugin:jsx-a11y/strict"], + "plugins": ["react-hooks", "jsx-a11y", "i18next"], + "extends": ["airbnb", "prettier", "prettier/react", "plugin:jsx-a11y/strict", "plugin:i18next/recommended"], "settings": { "react": { "version": "16.5.2" @@ -24,6 +24,7 @@ "window": true }, "rules": { + "i18next/no-literal-string": [2, {"markupOnly": true, "ignoreAttribute": ["to", "streamType", "path", "component", "variant", "key", "position", "promptName", "color","promptId", "headingLevel", "size", "target", "autoComplete","trigger", "from", "name", "fieldId", "css", "gutter", "dataCy", "tooltipMaxWidth", "mode", "aria-labelledby","aria-hidden","sortKey", "ouiaId", "credentialTypeNamespace", "link", "value", "credentialTypeKind", "linkTo", "scrollToAlignment", "displayKey", "sortedColumnKey", "maxHeight", "role", "aria-haspopup", "dropDirection", "resizeOrientation", "src", "theme"], "ignore":["Ansible", "Tower", "JSON", "YAML", "lg", "START"],"ignoreComponent":["code", "Omit","PotentialLink", "TypeRedirect", "Radio", "RunOnRadio", "NodeTypeLetter", "SelectableItem", "Dash"], "ignoreCallee": ["describe"] }], "camelcase": "off", "arrow-parens": "off", "comma-dangle": "off", diff --git a/awx/ui_next/package-lock.json b/awx/ui_next/package-lock.json index a64e834f55..70e18e4165 100644 --- a/awx/ui_next/package-lock.json +++ b/awx/ui_next/package-lock.json @@ -7172,6 +7172,15 @@ "lodash": "^4.17.15" } }, + "eslint-plugin-i18next": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-i18next/-/eslint-plugin-i18next-5.0.0.tgz", + "integrity": "sha512-ixbgSMrSb0dZsO6WPElg4JvPiQKLDA3ZpBuayxToADan1TKcbzKXT2A42Vyc0lEDhJRPL6uZnmm8vPjODDJypg==", + "dev": true, + "requires": { + "requireindex": "~1.1.0" + } + }, "eslint-plugin-import": { "version": "2.22.1", "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.22.1.tgz", @@ -15163,6 +15172,12 @@ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "dev": true }, + "requireindex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/requireindex/-/requireindex-1.1.0.tgz", + "integrity": "sha1-5UBLgVV+91225JxacgBIk/4D4WI=", + "dev": true + }, "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", diff --git a/awx/ui_next/package.json b/awx/ui_next/package.json index b052a3183f..7eb3759e74 100644 --- a/awx/ui_next/package.json +++ b/awx/ui_next/package.json @@ -43,6 +43,7 @@ "eslint-config-airbnb": "^17.1.0", "eslint-config-prettier": "^5.0.0", "eslint-import-resolver-webpack": "0.11.1", + "eslint-plugin-i18next": "^5.0.0", "eslint-plugin-import": "^2.14.0", "eslint-plugin-jsx-a11y": "^6.4.1", "eslint-plugin-react": "^7.11.1", diff --git a/awx/ui_next/src/components/CodeMirrorInput/VariablesDetail.jsx b/awx/ui_next/src/components/CodeMirrorInput/VariablesDetail.jsx index feb3ebb0b7..b5501fb0b7 100644 --- a/awx/ui_next/src/components/CodeMirrorInput/VariablesDetail.jsx +++ b/awx/ui_next/src/components/CodeMirrorInput/VariablesDetail.jsx @@ -1,6 +1,7 @@ import 'styled-components/macro'; import React, { useState, useEffect } from 'react'; import { node, number, oneOfType, shape, string, arrayOf } from 'prop-types'; +import { Trans, withI18n } from '@lingui/react'; import { Split, SplitItem, TextListItemVariants } from '@patternfly/react-core'; import { DetailName, DetailValue } from '../DetailList'; import MultiButtonToggle from '../MultiButtonToggle'; @@ -111,7 +112,7 @@ function VariablesDetail({ dataCy, helpText, value, label, rows, fullHeight }) { css="color: var(--pf-global--danger-color--100); font-size: var(--pf-global--FontSize--sm" > - Error: {error.message} + Error: {error.message} )} @@ -131,4 +132,4 @@ VariablesDetail.defaultProps = { helpText: '', }; -export default VariablesDetail; +export default withI18n()(VariablesDetail); diff --git a/awx/ui_next/src/components/CodeMirrorInput/VariablesDetail.test.jsx b/awx/ui_next/src/components/CodeMirrorInput/VariablesDetail.test.jsx index edb83d3515..9cf080e1ed 100644 --- a/awx/ui_next/src/components/CodeMirrorInput/VariablesDetail.test.jsx +++ b/awx/ui_next/src/components/CodeMirrorInput/VariablesDetail.test.jsx @@ -1,13 +1,13 @@ import React from 'react'; import { act } from 'react-dom/test-utils'; -import { shallow, mount } from 'enzyme'; +import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; import VariablesDetail from './VariablesDetail'; jest.mock('../../api'); describe('', () => { test('should render readonly CodeMirrorInput', () => { - const wrapper = shallow( + const wrapper = mountWithContexts( ); const input = wrapper.find('VariablesDetail___StyledCodeMirrorInput'); @@ -18,7 +18,7 @@ describe('', () => { }); test('should detect JSON', () => { - const wrapper = shallow( + const wrapper = mountWithContexts( ); const input = wrapper.find('VariablesDetail___StyledCodeMirrorInput'); @@ -28,7 +28,7 @@ describe('', () => { }); test('should convert between modes', () => { - const wrapper = shallow( + const wrapper = mountWithContexts( ); wrapper.find('MultiButtonToggle').invoke('onChange')('javascript'); @@ -43,7 +43,9 @@ describe('', () => { }); test('should render label and value= --- when there are no values', () => { - const wrapper = shallow(); + const wrapper = mountWithContexts( + + ); expect(wrapper.find('VariablesDetail___StyledCodeMirrorInput').length).toBe( 1 ); @@ -51,7 +53,7 @@ describe('', () => { }); test('should update value if prop changes', () => { - const wrapper = mount( + const wrapper = mountWithContexts( ); act(() => { @@ -67,13 +69,17 @@ describe('', () => { }); test('should default yaml value to "---"', () => { - const wrapper = shallow(); + const wrapper = mountWithContexts( + + ); const input = wrapper.find('VariablesDetail___StyledCodeMirrorInput'); expect(input.prop('value')).toEqual('---'); }); test('should default empty json to "{}"', () => { - const wrapper = mount(); + const wrapper = mountWithContexts( + + ); act(() => { wrapper.find('MultiButtonToggle').invoke('onChange')('javascript'); }); diff --git a/awx/ui_next/src/components/JobList/JobList.jsx b/awx/ui_next/src/components/JobList/JobList.jsx index f21e8bb15b..f4a39e839a 100644 --- a/awx/ui_next/src/components/JobList/JobList.jsx +++ b/awx/ui_next/src/components/JobList/JobList.jsx @@ -258,7 +258,7 @@ function JobList({ i18n, defaultParams, showTypeColumn = false }) { key="delete" onDelete={handleJobDelete} itemsToDelete={selected} - pluralizedItemName="Jobs" + pluralizedItemName={i18n._(t`Jobs`)} />, - {job.id} — {job.name} + {job.id} {job.name} diff --git a/awx/ui_next/src/components/Lookup/Lookup.jsx b/awx/ui_next/src/components/Lookup/Lookup.jsx index 2cfc284af8..d5d86b9f4d 100644 --- a/awx/ui_next/src/components/Lookup/Lookup.jsx +++ b/awx/ui_next/src/components/Lookup/Lookup.jsx @@ -103,7 +103,7 @@ function Lookup(props) {