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) {