diff --git a/.gitignore b/.gitignore index 642271f58e..eee0ebb8b9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules/ -coverage/ \ No newline at end of file +coverage/ +build/locales/_build \ No newline at end of file diff --git a/.linguirc b/.linguirc new file mode 100644 index 0000000000..7af86ec8ad --- /dev/null +++ b/.linguirc @@ -0,0 +1,5 @@ +{ + "localeDir": "build/locales/", + "srcPathDirs": ["src/"], + "format": "po" +} diff --git a/README.md b/README.md index 27e81f39dc..9d1413e7e0 100644 --- a/README.md +++ b/README.md @@ -12,3 +12,23 @@ * visit `https://127.0.0.1:3001/` **note:** These instructions assume you have the [awx](https://github.com/ansible/awx/blob/devel/CONTRIBUTING.md#running-the-environment) development api server up and running at `localhost:8043`. + +## Unit Tests + +To run the unit tests on files that you've changed: +* npm test + +To run a single test (in this case the login page test): +* npm test -- __tests__/pages/Login.jsx + +**note:** Once the test watcher is up and running you can hit `a` to run all the tests + +## Internationalization + +Internationalization leans on the [lingui](https://github.com/lingui/js-lingui) project. [Official documentation here](https://lingui.js.org/). We use this libary to mark our strings for translation. For common React use cases see [this link](https://lingui.js.org/tutorials/react-patterns.html). If you want to see this in action you'll need to take the following steps: + +1) `npm run add-locale` to add the language that you want to translate to (we should only have to do this once and the commit to repo afaik). Example: `npm run add-locale en es fr` # Add English, Spanish and French locale +2) `npm run extract-strings` to create .po files for each language specified. The .po files will be placed in src/locales but this is configurable. +3) Open up the .po file for the language you want to test and add some translations. In production we would pass this .po file off to the translation team. +4) Once you've edited your .po file (or we've gotten a .po file back from the translation team) run `npm run compile-strings`. This command takes the .po files and turns them into a minified JSON object and can be seen in the `messages.js` file in each locale directory. These files get loaded at the App root level (see: App.jsx). +5) Change the language in your browser and reload the page. You should see your specified translations in place of English strings. diff --git a/__tests__/components/About.test.jsx b/__tests__/components/About.test.jsx index f790a8561a..e2f101d095 100644 --- a/__tests__/components/About.test.jsx +++ b/__tests__/components/About.test.jsx @@ -1,5 +1,6 @@ import React from 'react'; import { mount } from 'enzyme'; +import { I18nProvider } from '@lingui/react'; import api from '../../src/api'; import { API_CONFIG } from '../../src/endpoints'; import About from '../../src/components/About'; @@ -9,14 +10,22 @@ describe('', () => { let closeButton; test('initially renders without crashing', () => { - aboutWrapper = mount(); + aboutWrapper = mount( + + + + ); expect(aboutWrapper.length).toBe(1); aboutWrapper.unmount(); }); test('close button calls onAboutModalClose', () => { const onAboutModalClose = jest.fn(); - aboutWrapper = mount(); + aboutWrapper = mount( + + + + ); closeButton = aboutWrapper.find('AboutModalBoxCloseButton Button'); closeButton.simulate('click'); expect(onAboutModalClose).toBeCalled(); @@ -29,9 +38,15 @@ describe('', () => { err.response = { status: 404, message: 'problem' }; return Promise.reject(err); }); - aboutWrapper = mount(); - await aboutWrapper.instance().componentDidMount(); - expect(aboutWrapper.state('error').response.status).toBe(404); + aboutWrapper = mount( + + + + ); + + const aboutComponentInstance = aboutWrapper.find(About).instance(); + await aboutComponentInstance.componentDidMount(); + expect(aboutComponentInstance.state.error.response.status).toBe(404); aboutWrapper.unmount(); }); diff --git a/__tests__/components/DataListToolbar.test.jsx b/__tests__/components/DataListToolbar.test.jsx index be5e028d37..c1c3a4e3af 100644 --- a/__tests__/components/DataListToolbar.test.jsx +++ b/__tests__/components/DataListToolbar.test.jsx @@ -1,5 +1,6 @@ import React from 'react'; import { mount } from 'enzyme'; +import { I18nProvider } from '@lingui/react'; import DataListToolbar from '../../src/components/DataListToolbar'; describe('', () => { @@ -15,7 +16,7 @@ describe('', () => { test('it triggers the expected callbacks', () => { const search = 'button[aria-label="Search"]'; - const searchTextInput = 'input[aria-label="search text input"]'; + const searchTextInput = 'input[aria-label="Search text input"]'; const selectAll = 'input[aria-label="Select all"]'; const sort = 'button[aria-label="Sort"]'; @@ -24,15 +25,17 @@ describe('', () => { const onSelectAll = jest.fn(); toolbar = mount( - + + + ); toolbar.find(sort).simulate('click'); diff --git a/__tests__/components/HelpDropdown.test.jsx b/__tests__/components/HelpDropdown.test.jsx index 85a15f0966..b2b9da1df1 100644 --- a/__tests__/components/HelpDropdown.test.jsx +++ b/__tests__/components/HelpDropdown.test.jsx @@ -1,15 +1,22 @@ import React from 'react'; import { mount } from 'enzyme'; +import { I18nProvider } from '@lingui/react'; import HelpDropdown from '../../src/components/HelpDropdown'; let questionCircleIcon; let dropdownWrapper; +let dropdownComponentInstance; let dropdownToggle; let dropdownItems; let dropdownItem; beforeEach(() => { - dropdownWrapper = mount(); + dropdownWrapper = mount( + + + + ); + dropdownComponentInstance = dropdownWrapper.find(HelpDropdown).instance(); }); afterEach(() => { @@ -19,14 +26,15 @@ afterEach(() => { describe('', () => { test('initially renders without crashing', () => { expect(dropdownWrapper.length).toBe(1); - expect(dropdownWrapper.state('isOpen')).toEqual(false); - expect(dropdownWrapper.state('showAboutModal')).toEqual(false); + expect(dropdownComponentInstance.state.isOpen).toEqual(false); + expect(dropdownComponentInstance.state.showAboutModal).toEqual(false); questionCircleIcon = dropdownWrapper.find('QuestionCircleIcon'); expect(questionCircleIcon.length).toBe(1); }); test('renders two dropdown items', () => { - dropdownWrapper.setState({ isOpen: true }); + dropdownComponentInstance.setState({ isOpen: true }); + dropdownWrapper.update(); dropdownItems = dropdownWrapper.find('DropdownItem'); expect(dropdownItems.length).toBe(2); const dropdownTexts = dropdownItems.map(item => item.text()); @@ -34,24 +42,27 @@ describe('', () => { }); test('onToggle sets state.isOpen to opposite', () => { - dropdownWrapper.setState({ isOpen: true }); + dropdownComponentInstance.setState({ isOpen: true }); + dropdownWrapper.update(); dropdownToggle = dropdownWrapper.find('DropdownToggle > DropdownToggle'); dropdownToggle.simulate('click'); - expect(dropdownWrapper.state('isOpen')).toEqual(false); + expect(dropdownComponentInstance.state.isOpen).toEqual(false); }); test('about dropdown item sets state.showAboutModal to true', () => { - dropdownWrapper.setState({ isOpen: true }); + dropdownComponentInstance.setState({ isOpen: true }); + dropdownWrapper.update(); dropdownItem = dropdownWrapper.find('DropdownItem a').at(1); dropdownItem.simulate('click'); - expect(dropdownWrapper.state('showAboutModal')).toEqual(true); + expect(dropdownComponentInstance.state.showAboutModal).toEqual(true); }); test('onAboutModalClose sets state.showAboutModal to false', () => { - dropdownWrapper.setState({ showAboutModal: true }); + dropdownComponentInstance.setState({ showAboutModal: true }); + dropdownWrapper.update(); const aboutModal = dropdownWrapper.find('AboutModal'); aboutModal.find('AboutModalBoxCloseButton Button').simulate('click'); - expect(dropdownWrapper.state('showAboutModal')).toEqual(false); + expect(dropdownComponentInstance.state.showAboutModal).toEqual(false); }); }); diff --git a/__tests__/components/LogoutButton.test.jsx b/__tests__/components/LogoutButton.test.jsx index e185193321..aaded3cd3f 100644 --- a/__tests__/components/LogoutButton.test.jsx +++ b/__tests__/components/LogoutButton.test.jsx @@ -1,5 +1,6 @@ import React from 'react'; import { mount } from 'enzyme'; +import { I18nProvider } from '@lingui/react'; import LogoutButton from '../../src/components/LogoutButton'; let buttonWrapper; @@ -14,7 +15,11 @@ const findChildren = () => { describe('', () => { test('initially renders without crashing', () => { const onDevLogout = jest.fn(); - buttonWrapper = mount(); + buttonWrapper = mount( + + + + ); findChildren(); expect(buttonWrapper.length).toBe(1); expect(buttonElem.length).toBe(1); diff --git a/__tests__/components/Pagination.test.jsx b/__tests__/components/Pagination.test.jsx index 7158c04471..93dbead8ec 100644 --- a/__tests__/components/Pagination.test.jsx +++ b/__tests__/components/Pagination.test.jsx @@ -1,34 +1,35 @@ import React from 'react'; import { mount } from 'enzyme'; +import { I18nProvider } from '@lingui/react'; import Pagination from '../../src/components/Pagination'; describe('', () => { - const noop = () => {}; - let pagination; afterEach(() => { - if (toolbar) { + if (pagination) { pagination.unmount(); pagination = null; } }); test('it triggers the expected callbacks on next and last', () => { - const next = 'button[aria-label="next"]'; - const last = 'button[aria-label="last"]'; + const next = 'button[aria-label="Next"]'; + const last = 'button[aria-label="Last"]'; const onSetPage = jest.fn(); pagination = mount( - + + + ); pagination.find(next).simulate('click'); @@ -43,20 +44,22 @@ describe('', () => { }); test('it triggers the expected callback on previous and first', () => { - const previous = 'button[aria-label="previous"]'; - const first = 'button[aria-label="first"]'; + const previous = 'button[aria-label="Previous"]'; + const first = 'button[aria-label="First"]'; const onSetPage = jest.fn(); pagination = mount( - + + + ); pagination.find(previous).simulate('click'); diff --git a/__tests__/components/TowerLogo.test.jsx b/__tests__/components/TowerLogo.test.jsx index 5a6561ff42..3bd40afaee 100644 --- a/__tests__/components/TowerLogo.test.jsx +++ b/__tests__/components/TowerLogo.test.jsx @@ -1,6 +1,7 @@ import React from 'react'; import { MemoryRouter } from 'react-router-dom'; import { mount } from 'enzyme'; +import { I18nProvider } from '@lingui/react'; import TowerLogo from '../../src/components/TowerLogo'; let logoWrapper; @@ -14,7 +15,13 @@ const findChildren = () => { describe('', () => { test('initially renders without crashing', () => { - logoWrapper = mount(); + logoWrapper = mount( + + + + + + ); findChildren(); expect(logoWrapper.length).toBe(1); expect(towerLogoElem.length).toBe(1); @@ -23,7 +30,13 @@ describe('', () => { test('adds navigation to route history on click', () => { const onLogoClick = jest.fn(); - logoWrapper = mount(); + logoWrapper = mount( + + + + + + ); findChildren(); expect(towerLogoElem.props().history.length).toBe(1); logoWrapper.simulate('click'); @@ -31,7 +44,13 @@ describe('', () => { }); test('gracefully handles not being passed click handler', () => { - logoWrapper = mount(); + logoWrapper = mount( + + + + + + ); findChildren(); expect(towerLogoElem.props().history.length).toBe(1); logoWrapper.simulate('click'); @@ -40,7 +59,13 @@ describe('', () => { test('handles mouse over and out state.hover changes', () => { const onLogoClick = jest.fn(); - logoWrapper = mount(); + logoWrapper = mount( + + + + + + ); findChildren(); findChildren(); expect(brandElem.props().src).toBe('tower-logo-header.svg'); diff --git a/__tests__/pages/Login.jsx b/__tests__/pages/Login.jsx index 4bac8b5af0..ed9fd164f9 100644 --- a/__tests__/pages/Login.jsx +++ b/__tests__/pages/Login.jsx @@ -1,6 +1,7 @@ import React from 'react'; import { MemoryRouter } from 'react-router-dom'; import { mount, shallow } from 'enzyme'; +import { I18nProvider } from '@lingui/react'; import { asyncFlush } from '../../jest.setup'; import AtLogin from '../../src/pages/Login'; import api from '../../src/api'; @@ -26,7 +27,13 @@ describe('', () => { }; beforeEach(() => { - loginWrapper = mount(); + loginWrapper = mount( + + + + + + ); findChildren(); }); @@ -49,7 +56,13 @@ describe('', () => { }); test('custom logo renders Brand component with correct src and alt', () => { - loginWrapper = mount(); + loginWrapper = mount( + + + + + + ); findChildren(); expect(loginHeaderLogo.length).toBe(1); expect(loginHeaderLogo.props().src).toBe('data:image/jpeg;images/foo.jpg'); @@ -57,7 +70,13 @@ describe('', () => { }); test('default logo renders Brand component with correct src and alt', () => { - loginWrapper = mount(); + loginWrapper = mount( + + + + + + ); findChildren(); expect(loginHeaderLogo.length).toBe(1); expect(loginHeaderLogo.props().src).toBe('tower-logo-header.svg'); diff --git a/__tests__/pages/Organizations/components/OrganizationDetail.test.jsx b/__tests__/pages/Organizations/components/OrganizationDetail.test.jsx index a160ad8773..a683582af0 100644 --- a/__tests__/pages/Organizations/components/OrganizationDetail.test.jsx +++ b/__tests__/pages/Organizations/components/OrganizationDetail.test.jsx @@ -1,17 +1,20 @@ import React from 'react'; import { mount } from 'enzyme'; import { MemoryRouter } from 'react-router-dom'; +import { I18nProvider } from '@lingui/react'; import OrganizationDetail from '../../../../src/pages/Organizations/components/OrganizationDetail'; describe('', () => { test('initially renders succesfully', () => { mount( - - - + + + + + ); }); }); diff --git a/__tests__/pages/Organizations/components/OrganizationListItem.test.jsx b/__tests__/pages/Organizations/components/OrganizationListItem.test.jsx index aab249b197..a1bea32b3f 100644 --- a/__tests__/pages/Organizations/components/OrganizationListItem.test.jsx +++ b/__tests__/pages/Organizations/components/OrganizationListItem.test.jsx @@ -1,14 +1,17 @@ import React from 'react'; import { mount } from 'enzyme'; import { MemoryRouter } from 'react-router-dom'; +import { I18nProvider } from '@lingui/react'; import OrganizationListItem from '../../../../src/pages/Organizations/components/OrganizationListItem'; describe('', () => { test('initially renders succesfully', () => { mount( - - - + + + + + ); }); }); diff --git a/__tests__/pages/Organizations/index.test.jsx b/__tests__/pages/Organizations/index.test.jsx index c9fc5359ab..293769f4fa 100644 --- a/__tests__/pages/Organizations/index.test.jsx +++ b/__tests__/pages/Organizations/index.test.jsx @@ -1,16 +1,19 @@ import React from 'react'; import { MemoryRouter } from 'react-router-dom'; import { mount } from 'enzyme'; +import { I18nProvider } from '@lingui/react'; import Organizations from '../../../src/pages/Organizations/index'; describe('', () => { test('initially renders succesfully', () => { mount( - + + + ); }); diff --git a/__tests__/pages/Organizations/views/Organization.view.test.jsx b/__tests__/pages/Organizations/views/Organization.view.test.jsx index c5dff0e2ef..9e388cb83c 100644 --- a/__tests__/pages/Organizations/views/Organization.view.test.jsx +++ b/__tests__/pages/Organizations/views/Organization.view.test.jsx @@ -1,17 +1,20 @@ import React from 'react'; import { mount } from 'enzyme'; import { MemoryRouter } from 'react-router-dom'; +import { I18nProvider } from '@lingui/react'; import OrganizationView from '../../../../src/pages/Organizations/views/Organization.view'; describe('', () => { test('initially renders succesfully', () => { mount( - - - + + + + + ); }); }); diff --git a/__tests__/pages/Organizations/views/Organizations.list.test.jsx b/__tests__/pages/Organizations/views/Organizations.list.test.jsx index e26717d554..79b01ff8fb 100644 --- a/__tests__/pages/Organizations/views/Organizations.list.test.jsx +++ b/__tests__/pages/Organizations/views/Organizations.list.test.jsx @@ -1,16 +1,19 @@ import React from 'react'; import { mount } from 'enzyme'; import { MemoryRouter } from 'react-router-dom'; +import { I18nProvider } from '@lingui/react'; import OrganizationsList from '../../../../src/pages/Organizations/views/Organizations.list'; describe('', () => { test('initially renders succesfully', () => { mount( - + + + ); }); diff --git a/babel.config.js b/babel.config.js index 7ddd59adca..87b4f38f68 100644 --- a/babel.config.js +++ b/babel.config.js @@ -2,7 +2,8 @@ module.exports = api => { api.cache(false); return { plugins: [ - '@babel/plugin-proposal-class-properties' + '@babel/plugin-proposal-class-properties', + 'macros' ], presets: [ ['@babel/preset-env', { diff --git a/build/locales/en/messages.js b/build/locales/en/messages.js new file mode 100644 index 0000000000..74712ae479 --- /dev/null +++ b/build/locales/en/messages.js @@ -0,0 +1 @@ +/* eslint-disable */module.exports={languageData:{"plurals":function(n,ord){var s=String(n).split("."),v0=!s[1],t0=Number(s[0])==n,n10=t0&&s[0].slice(-1),n100=t0&&s[0].slice(-2);if(ord)return n10==1&&n100!=11?"one":n10==2&&n100!=12?"two":n10==3&&n100!=13?"few":"other";return n==1&&v0?"one":"other"}},messages:{"> add":"> add","> edit":"> edit","About":"About","AboutModal Logo":"AboutModal Logo","Access":"Access","Add":"Add","Administration":"Administration","Admins":"Admins","Ansible Version":"Ansible Version","Applications":"Applications","Authentication":"Authentication","Authentication Settings":"Authentication Settings","Brand Image":"Brand Image","Collapse":"Collapse","Copyright 2018 Red Hat, Inc.":"Copyright 2018 Red Hat, Inc.","Created":"Created","Credential Types":"Credential Types","Credentials":"Credentials","Dashboard":"Dashboard","Delete":"Delete","Expand":"Expand","First":"First","Help":"Help","Instance Groups":"Instance Groups","Integrations":"Integrations","Invalid username or password. Please try again.":"Invalid username or password. Please try again.","Inventories":"Inventories","Inventory Scripts":"Inventory Scripts","Jobs":"Jobs","Jobs Settings":"Jobs Settings","Last":"Last","License":"License","Logout":"Logout","Management Jobs":"Management Jobs","Modified":"Modified","My View":"My View","Name":"Name","Next":"Next","Notification Templates":"Notification Templates","Notifications":"Notifications","Organization Add":"Organization Add","Organization detail tabs":"Organization detail tabs","Organizations":"Organizations","Organizations List":"Organizations List","Page <0/> of {pageCount}":function(a){return["Page <0/> of ",a("pageCount")]},"Page Number":"Page Number","Password":"Password","Per Page":"Per Page","Portal Mode":"Portal Mode","Previous":"Previous","Primary Navigation":"Primary Navigation","Projects":"Projects","Resources":"Resources","Schedules":"Schedules","Search":"Search","Search text input":"Search text input","Select all":"Select all","Settings":"Settings","Sort":"Sort","System":"System","System Settings":"System Settings","Teams":"Teams","Templates":"Templates","Tower Brand Image":"Tower Brand Image","User Interface":"User Interface","User Interface Settings":"User Interface Settings","Username":"Username","Users":"Users","Views":"Views","Welcome to Ansible Tower! Please Sign In.":"Welcome to Ansible Tower! Please Sign In.","add {currentTab}":function(a){return["add ",a("currentTab")]},"adding {currentTab}":function(a){return["adding ",a("currentTab")]},"confirm removal of {currentTab}/cancel and go back to {currentTab} view.":function(a){return["confirm removal of ",a("currentTab"),"/cancel and go back to ",a("currentTab")," view."]},"delete {currentTab}":function(a){return["delete ",a("currentTab")]},"deleting {currentTab} association with orgs":function(a){return["deleting ",a("currentTab")," association with orgs"]},"edit view":"edit view","save/cancel and go back to view":"save/cancel and go back to view","save/cancel and go back to {currentTab} view":function(a){return["save/cancel and go back to ",a("currentTab")," view"]},"select organization {itemId}":function(a){return["select organization ",a("itemId")]},"{currentTab} detail view":function(a){return[a("currentTab")," detail view"]},"{itemMin} - {itemMax} of {count}":function(a){return[a("itemMin")," - ",a("itemMax")," of ",a("count")]}}}; \ No newline at end of file diff --git a/build/locales/en/messages.po b/build/locales/en/messages.po new file mode 100644 index 0000000000..75bd3899d1 --- /dev/null +++ b/build/locales/en/messages.po @@ -0,0 +1,360 @@ +msgid "" +msgstr "" +"POT-Creation-Date: 2018-12-10 10:08-0500\n" +"Mime-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: @lingui/cli\n" +"Language: en\n" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: \n" +"Last-Translator: \n" +"Language-Team: \n" +"Plural-Forms: \n" + +#: src/pages/Organizations/components/OrganizationBreadcrumb.jsx:60 +msgid "> add" +msgstr "" + +#: src/pages/Organizations/components/OrganizationBreadcrumb.jsx:53 +msgid "> edit" +msgstr "" + +#: src/components/HelpDropdown.jsx:32 +msgid "About" +msgstr "" + +#: src/components/About.jsx:82 +msgid "AboutModal Logo" +msgstr "" + +#: src/App.jsx:235 +msgid "Access" +msgstr "" + +#: src/components/DataListToolbar/DataListToolbar.jsx:227 +#: src/components/DataListToolbar/DataListToolbar.jsx:228 +msgid "Add" +msgstr "" + +#: src/App.jsx:253 +msgid "Administration" +msgstr "" + +#: src/pages/Organizations/components/OrganizationListItem.jsx:66 +msgid "Admins" +msgstr "" + +#: src/components/About.jsx:100 +msgid "Ansible Version" +msgstr "" + +#: src/pages/Applications.jsx:17 +msgid "Applications" +msgstr "" + +#: src/App.jsx:283 +msgid "Authentication" +msgstr "" + +#: src/pages/AuthSettings.jsx:17 +msgid "Authentication Settings" +msgstr "" + +#: src/components/About.jsx:80 +msgid "Brand Image" +msgstr "" + +#: src/components/DataListToolbar/DataListToolbar.jsx:212 +msgid "Collapse" +msgstr "" + +#: src/components/About.jsx:78 +msgid "Copyright 2018 Red Hat, Inc." +msgstr "" + +#: src/pages/Organizations/views/Organizations.list.jsx:32 +msgid "Created" +msgstr "" + +#: src/App.jsx:257 +#: src/pages/CredentialTypes.jsx:17 +msgid "Credential Types" +msgstr "" + +#: src/App.jsx:217 +#: src/pages/Credentials.jsx:17 +msgid "Credentials" +msgstr "" + +#: src/App.jsx:191 +#: src/pages/Dashboard.jsx:17 +msgid "Dashboard" +msgstr "" + +#: src/components/DataListToolbar/DataListToolbar.jsx:220 +#: src/components/DataListToolbar/DataListToolbar.jsx:221 +msgid "Delete" +msgstr "" + +#: src/components/DataListToolbar/DataListToolbar.jsx:207 +msgid "Expand" +msgstr "" + +#: src/components/Pagination/Pagination.jsx:164 +msgid "First" +msgstr "" + +#: src/components/HelpDropdown.jsx:26 +msgid "Help" +msgstr "" + +#: src/App.jsx:269 +#: src/pages/InstanceGroups.jsx:17 +msgid "Instance Groups" +msgstr "" + +#: src/App.jsx:273 +msgid "Integrations" +msgstr "" + +#: src/pages/Login.jsx:80 +msgid "Invalid username or password. Please try again." +msgstr "" + +#: src/App.jsx:225 +#: src/pages/Inventories.jsx:17 +msgid "Inventories" +msgstr "" + +#: src/App.jsx:229 +#: src/pages/InventoryScripts.jsx:17 +msgid "Inventory Scripts" +msgstr "" + +#: src/App.jsx:195 +#: src/App.jsx:287 +#: src/pages/Jobs.jsx:17 +msgid "Jobs" +msgstr "" + +#: src/pages/JobsSettings.jsx:17 +msgid "Jobs Settings" +msgstr "" + +#: src/components/Pagination/Pagination.jsx:216 +msgid "Last" +msgstr "" + +#: src/App.jsx:299 +#: src/pages/License.jsx:17 +msgid "License" +msgstr "" + +#: src/components/LogoutButton.jsx:17 +msgid "Logout" +msgstr "" + +#: src/App.jsx:265 +#: src/pages/ManagementJobs.jsx:17 +msgid "Management Jobs" +msgstr "" + +#: src/pages/Organizations/views/Organizations.list.jsx:31 +msgid "Modified" +msgstr "" + +#: src/pages/Portal.jsx:17 +msgid "My View" +msgstr "" + +#: src/pages/Organizations/views/Organizations.list.jsx:30 +msgid "Name" +msgstr "" + +#: src/components/Pagination/Pagination.jsx:207 +msgid "Next" +msgstr "" + +#: src/pages/NotificationTemplates.jsx:17 +msgid "Notification Templates" +msgstr "" + +#: src/App.jsx:261 +msgid "Notifications" +msgstr "" + +#: src/pages/Organizations/views/Organization.add.jsx:15 +msgid "Organization Add" +msgstr "" + +#: src/pages/Organizations/components/OrganizationDetail.jsx:99 +msgid "Organization detail tabs" +msgstr "" + +#: src/App.jsx:239 +#: src/pages/Organizations/views/Organization.view.jsx:62 +#: src/pages/Organizations/views/Organizations.list.jsx:189 +#: src/pages/Organizations/views/Organizations.list.jsx:195 +msgid "Organizations" +msgstr "" + +#: src/pages/Organizations/views/Organizations.list.jsx:211 +msgid "Organizations List" +msgstr "" + +#: src/components/Pagination/Pagination.jsx:184 +msgid "Page <0/> of {pageCount}" +msgstr "" + +#: src/components/Pagination/Pagination.jsx:187 +msgid "Page Number" +msgstr "" + +#: src/pages/Login.jsx:76 +msgid "Password" +msgstr "" + +#: src/components/Pagination/Pagination.jsx:153 +msgid "Per Page" +msgstr "" + +#: src/App.jsx:203 +msgid "Portal Mode" +msgstr "" + +#: src/components/Pagination/Pagination.jsx:173 +msgid "Previous" +msgstr "" + +#: src/App.jsx:180 +msgid "Primary Navigation" +msgstr "" + +#: src/App.jsx:221 +#: src/pages/Projects.jsx:17 +msgid "Projects" +msgstr "" + +#: src/App.jsx:209 +msgid "Resources" +msgstr "" + +#: src/App.jsx:199 +#: src/pages/Schedules.jsx:17 +msgid "Schedules" +msgstr "" + +#: src/components/DataListToolbar/DataListToolbar.jsx:163 +msgid "Search" +msgstr "" + +#: src/components/DataListToolbar/DataListToolbar.jsx:157 +msgid "Search text input" +msgstr "" + +#: src/components/DataListToolbar/DataListToolbar.jsx:128 +msgid "Select all" +msgstr "" + +#: src/App.jsx:279 +msgid "Settings" +msgstr "" + +#: src/components/DataListToolbar/DataListToolbar.jsx:199 +msgid "Sort" +msgstr "" + +#: src/App.jsx:291 +msgid "System" +msgstr "" + +#: src/pages/SystemSettings.jsx:17 +msgid "System Settings" +msgstr "" + +#: src/App.jsx:247 +#: src/pages/Organizations/components/OrganizationListItem.jsx:58 +#: src/pages/Teams.jsx:17 +msgid "Teams" +msgstr "" + +#: src/App.jsx:213 +#: src/pages/Templates.jsx:17 +msgid "Templates" +msgstr "" + +#: src/components/TowerLogo/TowerLogo.jsx:48 +msgid "Tower Brand Image" +msgstr "" + +#: src/App.jsx:295 +msgid "User Interface" +msgstr "" + +#: src/pages/UISettings.jsx:17 +msgid "User Interface Settings" +msgstr "" + +#: src/pages/Login.jsx:73 +msgid "Username" +msgstr "" + +#: src/App.jsx:243 +#: src/pages/Organizations/components/OrganizationListItem.jsx:50 +#: src/pages/Users.jsx:17 +msgid "Users" +msgstr "" + +#: src/App.jsx:187 +msgid "Views" +msgstr "" + +#: src/pages/Login.jsx:70 +msgid "Welcome to Ansible Tower! Please Sign In." +msgstr "" + +#: src/pages/Organizations/components/OrganizationDetail.jsx:87 +msgid "add {currentTab}" +msgstr "" + +#: src/pages/Organizations/components/OrganizationDetail.jsx:76 +msgid "adding {currentTab}" +msgstr "" + +#: src/pages/Organizations/components/OrganizationDetail.jsx:69 +msgid "confirm removal of {currentTab}/cancel and go back to {currentTab} view." +msgstr "" + +#: src/pages/Organizations/components/OrganizationDetail.jsx:91 +msgid "delete {currentTab}" +msgstr "" + +#: src/pages/Organizations/components/OrganizationDetail.jsx:67 +msgid "deleting {currentTab} association with orgs" +msgstr "" + +#: src/pages/Organizations/components/OrganizationEdit.jsx:20 +msgid "edit view" +msgstr "" + +#: src/pages/Organizations/components/OrganizationEdit.jsx:22 +msgid "save/cancel and go back to view" +msgstr "" + +#: src/pages/Organizations/components/OrganizationDetail.jsx:78 +msgid "save/cancel and go back to {currentTab} view" +msgstr "" + +#: src/pages/Organizations/components/OrganizationListItem.jsx:30 +msgid "select organization {itemId}" +msgstr "" + +#: src/pages/Organizations/components/OrganizationDetail.jsx:85 +msgid "{currentTab} detail view" +msgstr "" + +#: src/components/Pagination/Pagination.jsx:158 +msgid "{itemMin} - {itemMax} of {count}" +msgstr "" diff --git a/build/locales/ja/messages.js b/build/locales/ja/messages.js new file mode 100644 index 0000000000..d8c61db44a --- /dev/null +++ b/build/locales/ja/messages.js @@ -0,0 +1 @@ +/* eslint-disable */module.exports={languageData:{"plurals":function(n,ord){if(ord)return"other";return"other"}},messages:{"> add":"> add","> edit":"> edit","About":"About","AboutModal Logo":"AboutModal Logo","Access":"Access","Add":"Add","Administration":"Administration","Admins":"Admins","Ansible Version":"Ansible Version","Applications":"Applications","Authentication":"Authentication","Authentication Settings":"Authentication Settings","Brand Image":"Brand Image","Collapse":"Collapse","Copyright 2018 Red Hat, Inc.":"Copyright 2018 Red Hat, Inc.","Created":"Created","Credential Types":"Credential Types","Credentials":"Credentials","Dashboard":"Dashboard","Delete":"Delete","Expand":"Expand","First":"First","Help":"Help","Instance Groups":"Instance Groups","Integrations":"Integrations","Invalid username or password. Please try again.":"Invalid username or password. Please try again.","Inventories":"Inventories","Inventory Scripts":"Inventory Scripts","Jobs":"Jobs","Jobs Settings":"Jobs Settings","Last":"Last","License":"License","Logout":"Logout","Management Jobs":"Management Jobs","Modified":"Modified","My View":"My View","Name":"Name","Next":"Next","Notification Templates":"Notification Templates","Notifications":"Notifications","Organization Add":"Organization Add","Organization detail tabs":"Organization detail tabs","Organizations":"Organizations","Organizations List":"Organizations List","Page <0/> of {pageCount}":function(a){return["Page <0/> of ",a("pageCount")]},"Page Number":"Page Number","Password":"Password","Per Page":"Per Page","Portal Mode":"Portal Mode","Previous":"Previous","Primary Navigation":"Primary Navigation","Projects":"Projects","Resources":"Resources","Schedules":"Schedules","Search":"Search","Search text input":"Search text input","Select all":"Select all","Settings":"Settings","Sort":"Sort","System":"System","System Settings":"System Settings","Teams":"Teams","Templates":"Templates","Tower Brand Image":"Tower Brand Image","User Interface":"User Interface","User Interface Settings":"User Interface Settings","Username":"Username","Users":"Users","Views":"Views","Welcome to Ansible Tower! Please Sign In.":"Welcome to Ansible Tower! Please Sign In.","add {currentTab}":function(a){return["add ",a("currentTab")]},"adding {currentTab}":function(a){return["adding ",a("currentTab")]},"confirm removal of {currentTab}/cancel and go back to {currentTab} view.":function(a){return["confirm removal of ",a("currentTab"),"/cancel and go back to ",a("currentTab")," view."]},"delete {currentTab}":function(a){return["delete ",a("currentTab")]},"deleting {currentTab} association with orgs":function(a){return["deleting ",a("currentTab")," association with orgs"]},"edit view":"edit view","save/cancel and go back to view":"save/cancel and go back to view","save/cancel and go back to {currentTab} view":function(a){return["save/cancel and go back to ",a("currentTab")," view"]},"select organization {itemId}":function(a){return["select organization ",a("itemId")]},"{currentTab} detail view":function(a){return[a("currentTab")," detail view"]},"{itemMin} - {itemMax} of {count}":function(a){return[a("itemMin")," - ",a("itemMax")," of ",a("count")]}}}; \ No newline at end of file diff --git a/build/locales/ja/messages.po b/build/locales/ja/messages.po new file mode 100644 index 0000000000..00a002f061 --- /dev/null +++ b/build/locales/ja/messages.po @@ -0,0 +1,360 @@ +msgid "" +msgstr "" +"POT-Creation-Date: 2018-12-10 10:08-0500\n" +"Mime-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: @lingui/cli\n" +"Language: ja\n" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: \n" +"Last-Translator: \n" +"Language-Team: \n" +"Plural-Forms: \n" + +#: src/pages/Organizations/components/OrganizationBreadcrumb.jsx:60 +msgid "> add" +msgstr "" + +#: src/pages/Organizations/components/OrganizationBreadcrumb.jsx:53 +msgid "> edit" +msgstr "" + +#: src/components/HelpDropdown.jsx:32 +msgid "About" +msgstr "" + +#: src/components/About.jsx:82 +msgid "AboutModal Logo" +msgstr "" + +#: src/App.jsx:235 +msgid "Access" +msgstr "" + +#: src/components/DataListToolbar/DataListToolbar.jsx:227 +#: src/components/DataListToolbar/DataListToolbar.jsx:228 +msgid "Add" +msgstr "" + +#: src/App.jsx:253 +msgid "Administration" +msgstr "" + +#: src/pages/Organizations/components/OrganizationListItem.jsx:66 +msgid "Admins" +msgstr "" + +#: src/components/About.jsx:100 +msgid "Ansible Version" +msgstr "" + +#: src/pages/Applications.jsx:17 +msgid "Applications" +msgstr "" + +#: src/App.jsx:283 +msgid "Authentication" +msgstr "" + +#: src/pages/AuthSettings.jsx:17 +msgid "Authentication Settings" +msgstr "" + +#: src/components/About.jsx:80 +msgid "Brand Image" +msgstr "" + +#: src/components/DataListToolbar/DataListToolbar.jsx:212 +msgid "Collapse" +msgstr "" + +#: src/components/About.jsx:78 +msgid "Copyright 2018 Red Hat, Inc." +msgstr "" + +#: src/pages/Organizations/views/Organizations.list.jsx:32 +msgid "Created" +msgstr "" + +#: src/App.jsx:257 +#: src/pages/CredentialTypes.jsx:17 +msgid "Credential Types" +msgstr "" + +#: src/App.jsx:217 +#: src/pages/Credentials.jsx:17 +msgid "Credentials" +msgstr "" + +#: src/App.jsx:191 +#: src/pages/Dashboard.jsx:17 +msgid "Dashboard" +msgstr "" + +#: src/components/DataListToolbar/DataListToolbar.jsx:220 +#: src/components/DataListToolbar/DataListToolbar.jsx:221 +msgid "Delete" +msgstr "" + +#: src/components/DataListToolbar/DataListToolbar.jsx:207 +msgid "Expand" +msgstr "" + +#: src/components/Pagination/Pagination.jsx:164 +msgid "First" +msgstr "" + +#: src/components/HelpDropdown.jsx:26 +msgid "Help" +msgstr "" + +#: src/App.jsx:269 +#: src/pages/InstanceGroups.jsx:17 +msgid "Instance Groups" +msgstr "" + +#: src/App.jsx:273 +msgid "Integrations" +msgstr "" + +#: src/pages/Login.jsx:80 +msgid "Invalid username or password. Please try again." +msgstr "" + +#: src/App.jsx:225 +#: src/pages/Inventories.jsx:17 +msgid "Inventories" +msgstr "" + +#: src/App.jsx:229 +#: src/pages/InventoryScripts.jsx:17 +msgid "Inventory Scripts" +msgstr "" + +#: src/App.jsx:195 +#: src/App.jsx:287 +#: src/pages/Jobs.jsx:17 +msgid "Jobs" +msgstr "" + +#: src/pages/JobsSettings.jsx:17 +msgid "Jobs Settings" +msgstr "" + +#: src/components/Pagination/Pagination.jsx:216 +msgid "Last" +msgstr "" + +#: src/App.jsx:299 +#: src/pages/License.jsx:17 +msgid "License" +msgstr "" + +#: src/components/LogoutButton.jsx:17 +msgid "Logout" +msgstr "" + +#: src/App.jsx:265 +#: src/pages/ManagementJobs.jsx:17 +msgid "Management Jobs" +msgstr "" + +#: src/pages/Organizations/views/Organizations.list.jsx:31 +msgid "Modified" +msgstr "" + +#: src/pages/Portal.jsx:17 +msgid "My View" +msgstr "" + +#: src/pages/Organizations/views/Organizations.list.jsx:30 +msgid "Name" +msgstr "" + +#: src/components/Pagination/Pagination.jsx:207 +msgid "Next" +msgstr "" + +#: src/pages/NotificationTemplates.jsx:17 +msgid "Notification Templates" +msgstr "" + +#: src/App.jsx:261 +msgid "Notifications" +msgstr "" + +#: src/pages/Organizations/views/Organization.add.jsx:15 +msgid "Organization Add" +msgstr "" + +#: src/pages/Organizations/components/OrganizationDetail.jsx:99 +msgid "Organization detail tabs" +msgstr "" + +#: src/App.jsx:239 +#: src/pages/Organizations/views/Organization.view.jsx:62 +#: src/pages/Organizations/views/Organizations.list.jsx:189 +#: src/pages/Organizations/views/Organizations.list.jsx:195 +msgid "Organizations" +msgstr "" + +#: src/pages/Organizations/views/Organizations.list.jsx:211 +msgid "Organizations List" +msgstr "" + +#: src/components/Pagination/Pagination.jsx:184 +msgid "Page <0/> of {pageCount}" +msgstr "" + +#: src/components/Pagination/Pagination.jsx:187 +msgid "Page Number" +msgstr "" + +#: src/pages/Login.jsx:76 +msgid "Password" +msgstr "" + +#: src/components/Pagination/Pagination.jsx:153 +msgid "Per Page" +msgstr "" + +#: src/App.jsx:203 +msgid "Portal Mode" +msgstr "" + +#: src/components/Pagination/Pagination.jsx:173 +msgid "Previous" +msgstr "" + +#: src/App.jsx:180 +msgid "Primary Navigation" +msgstr "" + +#: src/App.jsx:221 +#: src/pages/Projects.jsx:17 +msgid "Projects" +msgstr "" + +#: src/App.jsx:209 +msgid "Resources" +msgstr "" + +#: src/App.jsx:199 +#: src/pages/Schedules.jsx:17 +msgid "Schedules" +msgstr "" + +#: src/components/DataListToolbar/DataListToolbar.jsx:163 +msgid "Search" +msgstr "" + +#: src/components/DataListToolbar/DataListToolbar.jsx:157 +msgid "Search text input" +msgstr "" + +#: src/components/DataListToolbar/DataListToolbar.jsx:128 +msgid "Select all" +msgstr "" + +#: src/App.jsx:279 +msgid "Settings" +msgstr "" + +#: src/components/DataListToolbar/DataListToolbar.jsx:199 +msgid "Sort" +msgstr "" + +#: src/App.jsx:291 +msgid "System" +msgstr "" + +#: src/pages/SystemSettings.jsx:17 +msgid "System Settings" +msgstr "" + +#: src/App.jsx:247 +#: src/pages/Organizations/components/OrganizationListItem.jsx:58 +#: src/pages/Teams.jsx:17 +msgid "Teams" +msgstr "" + +#: src/App.jsx:213 +#: src/pages/Templates.jsx:17 +msgid "Templates" +msgstr "" + +#: src/components/TowerLogo/TowerLogo.jsx:48 +msgid "Tower Brand Image" +msgstr "" + +#: src/App.jsx:295 +msgid "User Interface" +msgstr "" + +#: src/pages/UISettings.jsx:17 +msgid "User Interface Settings" +msgstr "" + +#: src/pages/Login.jsx:73 +msgid "Username" +msgstr "" + +#: src/App.jsx:243 +#: src/pages/Organizations/components/OrganizationListItem.jsx:50 +#: src/pages/Users.jsx:17 +msgid "Users" +msgstr "" + +#: src/App.jsx:187 +msgid "Views" +msgstr "" + +#: src/pages/Login.jsx:70 +msgid "Welcome to Ansible Tower! Please Sign In." +msgstr "" + +#: src/pages/Organizations/components/OrganizationDetail.jsx:87 +msgid "add {currentTab}" +msgstr "" + +#: src/pages/Organizations/components/OrganizationDetail.jsx:76 +msgid "adding {currentTab}" +msgstr "" + +#: src/pages/Organizations/components/OrganizationDetail.jsx:69 +msgid "confirm removal of {currentTab}/cancel and go back to {currentTab} view." +msgstr "" + +#: src/pages/Organizations/components/OrganizationDetail.jsx:91 +msgid "delete {currentTab}" +msgstr "" + +#: src/pages/Organizations/components/OrganizationDetail.jsx:67 +msgid "deleting {currentTab} association with orgs" +msgstr "" + +#: src/pages/Organizations/components/OrganizationEdit.jsx:20 +msgid "edit view" +msgstr "" + +#: src/pages/Organizations/components/OrganizationEdit.jsx:22 +msgid "save/cancel and go back to view" +msgstr "" + +#: src/pages/Organizations/components/OrganizationDetail.jsx:78 +msgid "save/cancel and go back to {currentTab} view" +msgstr "" + +#: src/pages/Organizations/components/OrganizationListItem.jsx:30 +msgid "select organization {itemId}" +msgstr "" + +#: src/pages/Organizations/components/OrganizationDetail.jsx:85 +msgid "{currentTab} detail view" +msgstr "" + +#: src/components/Pagination/Pagination.jsx:158 +msgid "{itemMin} - {itemMax} of {count}" +msgstr "" diff --git a/jest.config.js b/jest.config.js index c3730195c8..db3216cbcb 100644 --- a/jest.config.js +++ b/jest.config.js @@ -2,6 +2,9 @@ module.exports = { collectCoverageFrom: [ 'src/**/*.{js,jsx}' ], + coveragePathIgnorePatterns: [ + '/src/locales' + ], moduleNameMapper: { '\\.(css|scss|less)$': '/__mocks__/styleMock.js' }, diff --git a/package-lock.json b/package-lock.json index 2011f86ff5..021ebbf790 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,36 +14,110 @@ } }, "@babel/core": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.1.2.tgz", - "integrity": "sha512-IFeSSnjXdhDaoysIlev//UzHZbdEmm7D0EIH2qtse9xK7mXEZQpYjs2P00XlP1qYsYvid79p+Zgg6tz1mp6iVw==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.2.0.tgz", + "integrity": "sha512-7pvAdC4B+iKjFFp9Ztj0QgBndJ++qaMeonT185wAqUnhipw8idm9Rv1UMyBuKtYjfl6ORNkgEgcsYLfHX/GpLw==", "dev": true, "requires": { "@babel/code-frame": "^7.0.0", - "@babel/generator": "^7.1.2", - "@babel/helpers": "^7.1.2", - "@babel/parser": "^7.1.2", + "@babel/generator": "^7.2.0", + "@babel/helpers": "^7.2.0", + "@babel/parser": "^7.2.0", "@babel/template": "^7.1.2", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.1.2", + "@babel/traverse": "^7.1.6", + "@babel/types": "^7.2.0", "convert-source-map": "^1.1.0", - "debug": "^3.1.0", - "json5": "^0.5.0", + "debug": "^4.1.0", + "json5": "^2.1.0", "lodash": "^4.17.10", "resolve": "^1.3.2", "semver": "^5.4.1", "source-map": "^0.5.0" }, "dependencies": { + "@babel/generator": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.2.0.tgz", + "integrity": "sha512-BA75MVfRlFQG2EZgFYIwyT1r6xSkwfP2bdkY/kLZusEYWiJs4xCowab/alaEaT0wSvmVuXGqiefeBlP+7V1yKg==", + "dev": true, + "requires": { + "@babel/types": "^7.2.0", + "jsesc": "^2.5.1", + "lodash": "^4.17.10", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + } + }, + "@babel/parser": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.2.0.tgz", + "integrity": "sha512-M74+GvK4hn1eejD9lZ7967qAwvqTZayQa3g10ag4s9uewgR7TKjeaT0YMyoq+gVfKYABiWZ4MQD701/t5e1Jhg==", + "dev": true + }, + "@babel/traverse": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.1.6.tgz", + "integrity": "sha512-CXedit6GpISz3sC2k2FsGCUpOhUqKdyL0lqNrImQojagnUMXf8hex4AxYFRuMkNGcvJX5QAFGzB5WJQmSv8SiQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.1.6", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "@babel/parser": "^7.1.6", + "@babel/types": "^7.1.6", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.10" + } + }, + "@babel/types": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.2.0.tgz", + "integrity": "sha512-b4v7dyfApuKDvmPb+O488UlGuR1WbwMXFsO/cyqMrnfvRAChZKJAYeeglWTjUO1b9UghKKgepAQM5tsvBJca6A==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.10", + "to-fast-properties": "^2.0.0" + } + }, "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz", + "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", "dev": true, "requires": { "ms": "^2.1.1" } }, + "globals": { + "version": "11.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.9.0.tgz", + "integrity": "sha512-5cJVtyXWH8PiJPVLZzzoIizXx944O4OmRro5MWKx5fT4MgcN7OfaMutPeaTdJCCURwbWdhhcCWcKIffPnmTzBg==", + "dev": true + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json5": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", + "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", @@ -286,14 +360,96 @@ } }, "@babel/helpers": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.1.2.tgz", - "integrity": "sha512-Myc3pUE8eswD73aWcartxB16K6CGmHDv9KxOmD2CeOs/FaEAQodr3VYGmlvOmog60vNQ2w8QbatuahepZwrHiA==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.2.0.tgz", + "integrity": "sha512-Fr07N+ea0dMcMN8nFpuK6dUIT7/ivt9yKQdEEnjVS83tG2pHwPi03gYmk/tyuwONnZ+sY+GFFPlWGgCtW1hF9A==", "dev": true, "requires": { "@babel/template": "^7.1.2", - "@babel/traverse": "^7.1.0", - "@babel/types": "^7.1.2" + "@babel/traverse": "^7.1.5", + "@babel/types": "^7.2.0" + }, + "dependencies": { + "@babel/generator": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.2.0.tgz", + "integrity": "sha512-BA75MVfRlFQG2EZgFYIwyT1r6xSkwfP2bdkY/kLZusEYWiJs4xCowab/alaEaT0wSvmVuXGqiefeBlP+7V1yKg==", + "dev": true, + "requires": { + "@babel/types": "^7.2.0", + "jsesc": "^2.5.1", + "lodash": "^4.17.10", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + } + }, + "@babel/parser": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.2.0.tgz", + "integrity": "sha512-M74+GvK4hn1eejD9lZ7967qAwvqTZayQa3g10ag4s9uewgR7TKjeaT0YMyoq+gVfKYABiWZ4MQD701/t5e1Jhg==", + "dev": true + }, + "@babel/traverse": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.1.6.tgz", + "integrity": "sha512-CXedit6GpISz3sC2k2FsGCUpOhUqKdyL0lqNrImQojagnUMXf8hex4AxYFRuMkNGcvJX5QAFGzB5WJQmSv8SiQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.1.6", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "@babel/parser": "^7.1.6", + "@babel/types": "^7.1.6", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.10" + } + }, + "@babel/types": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.2.0.tgz", + "integrity": "sha512-b4v7dyfApuKDvmPb+O488UlGuR1WbwMXFsO/cyqMrnfvRAChZKJAYeeglWTjUO1b9UghKKgepAQM5tsvBJca6A==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.10", + "to-fast-properties": "^2.0.0" + } + }, + "debug": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.0.tgz", + "integrity": "sha512-heNPJUJIqC+xB6ayLAMHaIrmN9HKa7aQO8MGqKpvCA+uJYVcvR6l5kgdrhRuwPFHU7P5/A1w0BjByPHwpfTDKg==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "globals": { + "version": "11.9.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.9.0.tgz", + "integrity": "sha512-5cJVtyXWH8PiJPVLZzzoIizXx944O4OmRro5MWKx5fT4MgcN7OfaMutPeaTdJCCURwbWdhhcCWcKIffPnmTzBg==", + "dev": true + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } } }, "@babel/highlight": { @@ -976,6 +1132,179 @@ "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.8.2.tgz", "integrity": "sha512-rLu3wcBWH4P5q1CGoSSH/i9hrXs7SlbRLkoq9IGuoPYNGQvDJ3pt/wmOM+XgYjIDRMVIdkUWt0RsfzF50JfnCw==" }, + "@lingui/babel-plugin-extract-messages": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@lingui/babel-plugin-extract-messages/-/babel-plugin-extract-messages-2.7.2.tgz", + "integrity": "sha512-YKyB0avVZteskOeXsJCTO+346FfhTCmhF4W4rG4nwRbyIeTOYL5heBL54g1e+T5YXBJLi5HJuhRd1OGuGzbQzg==", + "dev": true, + "requires": { + "@lingui/conf": "2.7.2", + "babel-generator": "^6.26.1" + } + }, + "@lingui/babel-plugin-transform-js": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@lingui/babel-plugin-transform-js/-/babel-plugin-transform-js-2.7.2.tgz", + "integrity": "sha512-V2avCZOqiyejz4vM24X+Wz1+bvzdovLUdW9iBRocaH6hcRtA1ttVQ6JAQBw/tACY5sFw73LdrPiVMiD7dw1NtA==", + "dev": true + }, + "@lingui/babel-plugin-transform-react": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@lingui/babel-plugin-transform-react/-/babel-plugin-transform-react-2.7.2.tgz", + "integrity": "sha512-50+GM9LL7V4mB6ekY7hUGmyMLewDQ9bzVXTyRtbTl/78xJoQKSv8Wuz+jlvPcP0fKAFcmcHo3QJPPOkSAbgnOw==", + "dev": true + }, + "@lingui/cli": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@lingui/cli/-/cli-2.7.2.tgz", + "integrity": "sha512-PdSUALHUyHG7iwwoECWqUlvWjI5jg+9TUWJMgnLyelGi/th6EAdhs/DPxT1uYWQl438hYXLRN61QrPzKtKgZHQ==", + "dev": true, + "requires": { + "@lingui/babel-plugin-extract-messages": "2.7.2", + "@lingui/babel-plugin-transform-js": "2.7.2", + "@lingui/babel-plugin-transform-react": "2.7.2", + "@lingui/conf": "2.7.2", + "babel-generator": "^6.26.1", + "babel-plugin-syntax-jsx": "^6.18.0", + "babel-runtime": "^6.26.0", + "babel-types": "^6.26.0", + "babylon": "^6.18.0", + "bcp-47": "^1.0.4", + "chalk": "^2.3.0", + "cli-table": "^0.3.1", + "commander": "^2.17.1", + "date-fns": "^1.29.0", + "fuzzaldrin": "^2.1.0", + "glob": "^7.1.2", + "inquirer": "^6.2.0", + "make-plural": "^4.1.1", + "messageformat-parser": "^2.0.0", + "mkdirp": "^0.5.1", + "opencollective": "^1.0.3", + "ora": "^3.0.0", + "pofile": "^1.0.11", + "pseudolocale": "^1.1.0", + "ramda": "^0.25.0", + "typescript": "^2.9.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@lingui/conf": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@lingui/conf/-/conf-2.7.2.tgz", + "integrity": "sha512-SMTY4GWaP611hEnWm4YiPXp6jufD+qzH6RUiDe+r9aX5j9kMXV2/aYQfNezbh46BpLFf29xxm+Wn5q89/fRbIw==", + "dev": true, + "requires": { + "chalk": "^2.3.0", + "cosmiconfig": "^5.0.6", + "jest-regex-util": "^23.3.0", + "jest-validate": "^23.5.0", + "pkg-conf": "^2.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@lingui/core": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@lingui/core/-/core-2.7.2.tgz", + "integrity": "sha512-LLMNcxfXmjhxG18sQmIb4azNuwVyhMUhcVFgOQ682eVQEGaSIncPsnSQRGhgYbiqY1LGXlZEXZnYdyyDMSZR0A==", + "requires": { + "babel-runtime": "^6.26.0", + "make-plural": "^4.1.1", + "messageformat-parser": "^2.0.0" + } + }, + "@lingui/macro": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@lingui/macro/-/macro-2.7.2.tgz", + "integrity": "sha512-kU5fl/2MvHQLfVRju2QR28uKOHsUqlLZOJwMXNAm/eq42D6ORa5vZR2ovlBRF9IdcYGqkCCPjeTLN5NC7b5gyQ==", + "dev": true, + "requires": { + "@lingui/babel-plugin-transform-react": "2.7.2", + "babel-plugin-macros": "^2.2.0" + } + }, + "@lingui/react": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@lingui/react/-/react-2.7.2.tgz", + "integrity": "sha512-dYfhojpYLKyXp3V1i3twjipIXGK80rBBLNMZOXBBCqm5Lypef3d7Ip1jLXuhk4Ni++ijWJfHC40F3gWNBNFSjw==", + "requires": { + "@lingui/core": "2.7.2", + "babel-runtime": "^6.26.0", + "hash-sum": "^1.0.2", + "hoist-non-react-statics": "3.0.1", + "prop-types": "^15.6.2" + }, + "dependencies": { + "hoist-non-react-statics": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.0.1.tgz", + "integrity": "sha512-1kXwPsOi0OGQIZNVMPvgWJ9tSnGMiMfJdihqEzrPEXlHOBh9AAHXX/QYmAJTXztnz/K+PQ8ryCb4eGaN6HlGbQ==", + "requires": { + "react-is": "^16.3.2" + } + } + } + }, "@patternfly/patternfly-next": { "version": "1.0.84", "resolved": "https://registry.npmjs.org/@patternfly/patternfly-next/-/patternfly-next-1.0.84.tgz", @@ -2461,6 +2790,25 @@ "babel-types": "^6.24.1" } }, + "babel-polyfill": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.23.0.tgz", + "integrity": "sha1-g2TKYt+Or7gwSZ9pkXdGbDsDSZ0=", + "dev": true, + "requires": { + "babel-runtime": "^6.22.0", + "core-js": "^2.4.0", + "regenerator-runtime": "^0.10.0" + }, + "dependencies": { + "regenerator-runtime": { + "version": "0.10.5", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz", + "integrity": "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg=", + "dev": true + } + } + }, "babel-preset-fbjs": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/babel-preset-fbjs/-/babel-preset-fbjs-2.3.0.tgz", @@ -2697,6 +3045,17 @@ "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=", "dev": true }, + "bcp-47": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/bcp-47/-/bcp-47-1.0.4.tgz", + "integrity": "sha512-KquGHKBVXDBnOOntjqkqINNyNX0eKhDXYbK+83pDJXWO7lV6D7Ey1IQNIDbVQOHxNv6rdynnfS/RfPLVz5X0WA==", + "dev": true, + "requires": { + "is-alphabetical": "^1.0.0", + "is-alphanumerical": "^1.0.0", + "is-decimal": "^1.0.0" + } + }, "bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", @@ -3354,6 +3713,29 @@ "restore-cursor": "^2.0.0" } }, + "cli-spinners": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-1.3.1.tgz", + "integrity": "sha512-1QL4544moEsDVH9T/l6Cemov/37iv1RtoKf7NJ04A60+4MREXNfx/QvavbH6QoGdsD4N4Mwy49cmaINR/o2mdg==", + "dev": true + }, + "cli-table": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cli-table/-/cli-table-0.3.1.tgz", + "integrity": "sha1-9TsFJmqLGguTSz0IIebi3FkUriM=", + "dev": true, + "requires": { + "colors": "1.0.3" + }, + "dependencies": { + "colors": { + "version": "1.0.3", + "resolved": "http://registry.npmjs.org/colors/-/colors-1.0.3.tgz", + "integrity": "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs=", + "dev": true + } + } + }, "cli-width": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", @@ -3388,6 +3770,12 @@ } } }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "dev": true + }, "clone-deep": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-2.0.2.tgz", @@ -3933,6 +4321,12 @@ } } }, + "date-fns": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.29.0.tgz", + "integrity": "sha512-lbTXWZ6M20cWH8N9S6afb0SBm6tMk+uUg6z3MqHPKE9atmsY3kJkTm8vKe93izJ2B2+q5MV990sM2CHgtAZaOw==", + "dev": true + }, "date-now": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", @@ -4018,6 +4412,15 @@ "strip-bom": "^2.0.0" } }, + "defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "dev": true, + "requires": { + "clone": "^1.0.2" + } + }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -4428,6 +4831,15 @@ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", "dev": true }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "dev": true, + "requires": { + "iconv-lite": "~0.4.13" + } + }, "end-of-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", @@ -6226,6 +6638,12 @@ "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "dev": true }, + "fuzzaldrin": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fuzzaldrin/-/fuzzaldrin-2.1.0.tgz", + "integrity": "sha1-kCBMPi/appQbso0WZF1BgGOpDps=", + "dev": true + }, "gauge": { "version": "2.7.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", @@ -6532,6 +6950,11 @@ "safe-buffer": "^5.0.1" } }, + "hash-sum": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=" + }, "hash.js": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.5.tgz", @@ -7310,6 +7733,22 @@ } } }, + "is-alphabetical": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.2.tgz", + "integrity": "sha512-V0xN4BYezDHcBSKb1QHUFMlR4as/XEuCZBzMJUU4n7+Cbt33SmUnSol+pnXFvLxSHNq2CemUXNdaXV6Flg7+xg==", + "dev": true + }, + "is-alphanumerical": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.2.tgz", + "integrity": "sha512-pyfU/0kHdISIgslFfZN9nfY1Gk3MquQgUm1mJTjdkEPpkAKNWuBTSqFwewOpR7N351VkErCiyV71zX7mlQQqsg==", + "dev": true, + "requires": { + "is-alphabetical": "^1.0.0", + "is-decimal": "^1.0.0" + } + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -7385,6 +7824,12 @@ "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", "dev": true }, + "is-decimal": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.2.tgz", + "integrity": "sha512-TRzl7mOCchnhchN+f3ICUCzYvL9ul7R+TYOsZ8xia++knyZAJfv/uA1FvQXsAnYIl1T3B2X5E/J7Wb1QXiIBXg==", + "dev": true + }, "is-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", @@ -8948,6 +9393,46 @@ "integrity": "sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=", "dev": true }, + "log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dev": true, + "requires": { + "chalk": "^2.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "loglevel": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.1.tgz", @@ -9003,6 +9488,22 @@ } } }, + "make-plural": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/make-plural/-/make-plural-4.3.0.tgz", + "integrity": "sha512-xTYd4JVHpSCW+aqDof6w/MebaMVNTVYBZhbB/vi513xXdiPT92JMVCo0Jq8W2UZnzYRFeVbQiQ+I25l13JuKvA==", + "requires": { + "minimist": "^1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "optional": true + } + } + }, "makeerror": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", @@ -9195,6 +9696,11 @@ } } }, + "messageformat-parser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/messageformat-parser/-/messageformat-parser-2.0.0.tgz", + "integrity": "sha512-C2ZjB5GlLeikkeoMCTcwEeb68LrFl9osxQzXHIPh0Wcj+43wNsoKpRRKq9rm204sAIdknrdcoeQMUnzvDuMf6g==" + }, "methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -9589,6 +10095,16 @@ "lower-case": "^1.1.1" } }, + "node-fetch": { + "version": "1.6.3", + "resolved": "http://registry.npmjs.org/node-fetch/-/node-fetch-1.6.3.tgz", + "integrity": "sha1-3CNO3WSJmC1Y6PDbT2lQKavNjAQ=", + "dev": true, + "requires": { + "encoding": "^0.1.11", + "is-stream": "^1.0.1" + } + }, "node-forge": { "version": "0.7.5", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.7.5.tgz", @@ -10047,6 +10563,82 @@ "mimic-fn": "^1.0.0" } }, + "opencollective": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/opencollective/-/opencollective-1.0.3.tgz", + "integrity": "sha1-ruY3K8KBRFg2kMPKja7PwSDdDvE=", + "dev": true, + "requires": { + "babel-polyfill": "6.23.0", + "chalk": "1.1.3", + "inquirer": "3.0.6", + "minimist": "1.2.0", + "node-fetch": "1.6.3", + "opn": "4.0.2" + }, + "dependencies": { + "ansi-escapes": { + "version": "1.4.0", + "resolved": "http://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", + "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", + "dev": true + }, + "chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", + "dev": true + }, + "external-editor": { + "version": "2.2.0", + "resolved": "http://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", + "dev": true, + "requires": { + "chardet": "^0.4.0", + "iconv-lite": "^0.4.17", + "tmp": "^0.0.33" + } + }, + "inquirer": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.0.6.tgz", + "integrity": "sha1-4EqqnQW3o8ubD0B9BDdfBEcZA0c=", + "dev": true, + "requires": { + "ansi-escapes": "^1.1.0", + "chalk": "^1.0.0", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^2.0.1", + "figures": "^2.0.0", + "lodash": "^4.3.0", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rx": "^4.1.0", + "string-width": "^2.0.0", + "strip-ansi": "^3.0.0", + "through": "^2.3.6" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "opn": { + "version": "4.0.2", + "resolved": "http://registry.npmjs.org/opn/-/opn-4.0.2.tgz", + "integrity": "sha1-erwi5kTf9jsKltWrfyeQwPAavJU=", + "dev": true, + "requires": { + "object-assign": "^4.0.1", + "pinkie-promise": "^2.0.0" + } + } + } + }, "opn": { "version": "5.4.0", "resolved": "https://registry.npmjs.org/opn/-/opn-5.4.0.tgz", @@ -10087,6 +10679,66 @@ "wordwrap": "~1.0.0" } }, + "ora": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-3.0.0.tgz", + "integrity": "sha512-LBS97LFe2RV6GJmXBi6OKcETKyklHNMV0xw7BtsVn2MlsgsydyZetSCbCANr+PFLmDyv4KV88nn0eCKza665Mg==", + "dev": true, + "requires": { + "chalk": "^2.3.1", + "cli-cursor": "^2.1.0", + "cli-spinners": "^1.1.0", + "log-symbols": "^2.2.0", + "strip-ansi": "^4.0.0", + "wcwidth": "^1.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, "original": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz", @@ -10379,6 +11031,42 @@ "pinkie": "^2.0.0" } }, + "pkg-conf": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pkg-conf/-/pkg-conf-2.1.0.tgz", + "integrity": "sha1-ISZRTKbyq/69FoWW3xi6V4Z/AFg=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "load-json-file": "^4.0.0" + }, + "dependencies": { + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, "pkg-dir": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", @@ -10411,6 +11099,12 @@ "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==" }, + "pofile": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pofile/-/pofile-1.0.11.tgz", + "integrity": "sha512-Vy9eH1dRD9wHjYt/QqXcTz+RnX/zg53xK+KljFSX30PvdDMb2z+c6uDUeblUGqqJgz3QFsdlA0IJvHziPmWtQg==", + "dev": true + }, "portfinder": { "version": "1.0.19", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.19.tgz", @@ -10624,6 +11318,15 @@ "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", "dev": true }, + "pseudolocale": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pseudolocale/-/pseudolocale-1.1.0.tgz", + "integrity": "sha512-OZ8I/hwYEJ3beN3IEcNnt8EpcqblH0/x23hulKBXjs+WhTTEle+ijCHCkh2bd+cIIeCuCwSCbBe93IthGG6hLw==", + "dev": true, + "requires": { + "commander": "*" + } + }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -10712,6 +11415,12 @@ "integrity": "sha1-635iZ1SN3t+4mcG5Dlc3RVnN234=", "dev": true }, + "ramda": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.25.0.tgz", + "integrity": "sha512-GXpfrYVPwx3K7RQ6aYT8KPS8XViSXUVJT1ONhoKPE9VAleW42YE+U+8VEyGWt41EnEQW7gwecYJriTI0pKoecQ==", + "dev": true + }, "randexp": { "version": "0.4.6", "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz", @@ -10834,8 +11543,7 @@ "react-is": { "version": "16.6.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.6.0.tgz", - "integrity": "sha512-q8U7k0Fi7oxF1HvQgyBjPwDXeMplEsArnKt2iYhuIF86+GBbgLHdAmokL3XUFjTd7Q363OSNG55FOGUdONVn1g==", - "dev": true + "integrity": "sha512-q8U7k0Fi7oxF1HvQgyBjPwDXeMplEsArnKt2iYhuIF86+GBbgLHdAmokL3XUFjTd7Q363OSNG55FOGUdONVn1g==" }, "react-lifecycles-compat": { "version": "3.0.4", @@ -11628,6 +12336,12 @@ "aproba": "^1.1.1" } }, + "rx": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz", + "integrity": "sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=", + "dev": true + }, "rxjs": { "version": "6.3.3", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.3.3.tgz", @@ -13387,6 +14101,12 @@ "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", "dev": true }, + "typescript": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.9.2.tgz", + "integrity": "sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w==", + "dev": true + }, "uglify-js": { "version": "3.4.9", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz", @@ -13834,6 +14554,15 @@ "minimalistic-assert": "^1.0.0" } }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "dev": true, + "requires": { + "defaults": "^1.0.3" + } + }, "webidl-conversions": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", diff --git a/package.json b/package.json index 19dad2c599..833f11652c 100644 --- a/package.json +++ b/package.json @@ -6,21 +6,27 @@ "scripts": { "start": "webpack-dev-server --config ./webpack.config.js --mode development", "test": "jest --watch --coverage", - "lint": "./node_modules/eslint/bin/eslint.js src/**/*.js src/**/*.jsx" + "lint": "./node_modules/eslint/bin/eslint.js src/**/*.js src/**/*.jsx", + "add-locale": "lingui add-locale", + "extract-strings": "lingui extract", + "compile-strings": "lingui compile" }, "keywords": [], "author": "", "license": "Apache", "devDependencies": { - "@babel/core": "^7.1.2", + "@babel/core": "^7.2.0", "@babel/plugin-proposal-class-properties": "^7.1.0", "@babel/polyfill": "^7.0.0", "@babel/preset-env": "^7.1.0", "@babel/preset-react": "^7.0.0", + "@lingui/cli": "^2.7.2", + "@lingui/macro": "^2.7.2", "babel-core": "^7.0.0-bridge.0", "babel-eslint": "^10.0.1", "babel-jest": "^23.6.0", "babel-loader": "^8.0.4", + "babel-plugin-macros": "^2.4.2", "css-loader": "^1.0.0", "enzyme": "^3.7.0", "enzyme-adapter-react-16": "^1.6.0", @@ -40,6 +46,7 @@ "webpack-dev-server": "^3.1.4" }, "dependencies": { + "@lingui/react": "^2.7.2", "@patternfly/patternfly-next": "^1.0.84", "@patternfly/react-core": "^1.37.2", "@patternfly/react-icons": "^2.9.1", diff --git a/src/App.jsx b/src/App.jsx index f400ce3e53..69e300dd75 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,4 +1,6 @@ import React, { Fragment } from 'react'; +import { I18nProvider, I18n } from '@lingui/react'; +import { t } from '@lingui/macro'; import { Redirect, Switch, @@ -53,6 +55,18 @@ import Teams from './pages/Teams'; import Templates from './pages/Templates'; import Users from './pages/Users'; +import ja from '../build/locales/ja/messages'; +import en from '../build/locales/en/messages'; + +const catalogs = { en, ja }; + +// This spits out the language and the region. Example: es-US +const language = (navigator.languages && navigator.languages[0]) +|| navigator.language +|| navigator.userLanguage; + +const languageWithoutRegionCode = language.toLowerCase().split(/[_-]+/)[0]; + const SideNavItems = ({ items, history }) => { const currentPath = history.location.pathname.split('/')[1]; let activeGroup; @@ -130,195 +144,201 @@ class App extends React.Component { ); return ( - - - - api.isAuthenticated()} redirectPath="/" path="/login" component={() => } /> - - } - toolbar={PageToolbar} - showNavToggle - onNavToggle={this.onNavToggle} - /> - )} - sidebar={( - - - - - - )} - /> - )} - useCondensed - > - !api.isAuthenticated()} redirectPath="/login" exact path="/" component={() => ()} /> - !api.isAuthenticated()} redirectPath="/login" path="/home" component={Dashboard} /> - !api.isAuthenticated()} redirectPath="/login" path="/jobs" component={Jobs} /> - !api.isAuthenticated()} redirectPath="/login" path="/schedules" component={Schedules} /> - !api.isAuthenticated()} redirectPath="/login" path="/portal" component={Portal} /> - !api.isAuthenticated()} redirectPath="/login" path="/templates" component={Templates} /> - !api.isAuthenticated()} redirectPath="/login" path="/credentials" component={Credentials} /> - !api.isAuthenticated()} redirectPath="/login" path="/projects" component={Projects} /> - !api.isAuthenticated()} redirectPath="/login" path="/inventories" component={Inventories} /> - !api.isAuthenticated()} redirectPath="/login" path="/inventory_scripts" component={InventoryScripts} /> - !api.isAuthenticated()} redirectPath="/login" path="/organizations" component={Organizations} /> - !api.isAuthenticated()} redirectPath="/login" path="/users" component={Users} /> - !api.isAuthenticated()} redirectPath="/login" path="/teams" component={Teams} /> - !api.isAuthenticated()} redirectPath="/login" path="/credential_types" component={CredentialTypes} /> - !api.isAuthenticated()} redirectPath="/login" path="/notification_templates" component={NotificationTemplates} /> - !api.isAuthenticated()} redirectPath="/login" path="/management_jobs" component={ManagementJobs} /> - !api.isAuthenticated()} redirectPath="/login" path="/instance_groups" component={InstanceGroups} /> - !api.isAuthenticated()} redirectPath="/login" path="/applications" component={Applications} /> - !api.isAuthenticated()} redirectPath="/login" path="/auth_settings" component={AuthSettings} /> - !api.isAuthenticated()} redirectPath="/login" path="/jobs_settings" component={JobsSettings} /> - !api.isAuthenticated()} redirectPath="/login" path="/system_settings" component={SystemSettings} /> - !api.isAuthenticated()} redirectPath="/login" path="/ui_settings" component={UISettings} /> - !api.isAuthenticated()} redirectPath="/login" path="/license" component={License} /> - - - - + + + + + api.isAuthenticated()} redirectPath="/" path="/login" component={() => } /> + + } + toolbar={PageToolbar} + showNavToggle + onNavToggle={this.onNavToggle} + /> + )} + sidebar={( + + {({ i18n }) => ( + + )} + + )} + /> + )} + useCondensed + > + !api.isAuthenticated()} redirectPath="/login" exact path="/" component={() => ()} /> + !api.isAuthenticated()} redirectPath="/login" path="/home" component={Dashboard} /> + !api.isAuthenticated()} redirectPath="/login" path="/jobs" component={Jobs} /> + !api.isAuthenticated()} redirectPath="/login" path="/schedules" component={Schedules} /> + !api.isAuthenticated()} redirectPath="/login" path="/portal" component={Portal} /> + !api.isAuthenticated()} redirectPath="/login" path="/templates" component={Templates} /> + !api.isAuthenticated()} redirectPath="/login" path="/credentials" component={Credentials} /> + !api.isAuthenticated()} redirectPath="/login" path="/projects" component={Projects} /> + !api.isAuthenticated()} redirectPath="/login" path="/inventories" component={Inventories} /> + !api.isAuthenticated()} redirectPath="/login" path="/inventory_scripts" component={InventoryScripts} /> + !api.isAuthenticated()} redirectPath="/login" path="/organizations" component={Organizations} /> + !api.isAuthenticated()} redirectPath="/login" path="/users" component={Users} /> + !api.isAuthenticated()} redirectPath="/login" path="/teams" component={Teams} /> + !api.isAuthenticated()} redirectPath="/login" path="/credential_types" component={CredentialTypes} /> + !api.isAuthenticated()} redirectPath="/login" path="/notification_templates" component={NotificationTemplates} /> + !api.isAuthenticated()} redirectPath="/login" path="/management_jobs" component={ManagementJobs} /> + !api.isAuthenticated()} redirectPath="/login" path="/instance_groups" component={InstanceGroups} /> + !api.isAuthenticated()} redirectPath="/login" path="/applications" component={Applications} /> + !api.isAuthenticated()} redirectPath="/login" path="/auth_settings" component={AuthSettings} /> + !api.isAuthenticated()} redirectPath="/login" path="/jobs_settings" component={JobsSettings} /> + !api.isAuthenticated()} redirectPath="/login" path="/system_settings" component={SystemSettings} /> + !api.isAuthenticated()} redirectPath="/login" path="/ui_settings" component={UISettings} /> + !api.isAuthenticated()} redirectPath="/login" path="/license" component={License} /> + + + + + ); } } diff --git a/src/components/About.jsx b/src/components/About.jsx index 861e15165d..e5e8254e34 100644 --- a/src/components/About.jsx +++ b/src/components/About.jsx @@ -1,4 +1,6 @@ import React from 'react'; +import { I18n } from '@lingui/react'; +import { Trans, t } from '@lingui/macro'; import { AboutModal, TextContent, @@ -67,37 +69,43 @@ class About extends React.Component { const { ansible_version = 'loading', version = 'loading' } = config; return ( - -
-          { this.createSpeechBubble(version) }
-          {`
-          \\
-           \\  ^__^
-              (oo)\\_______
-              (__)      A )\\
-                  ||----w |
-                  ||     ||
-                    `}
-        
+ + {({ i18n }) => ( + +
+              { this.createSpeechBubble(version) }
+              {`
+              \\
+              \\  ^__^
+                  (oo)\\_______
+                  (__)      A )\\
+                      ||----w |
+                      ||     ||
+                        `}
+            
- - - Ansible Version - { ansible_version } - - - { error ?
error
: ''} -
+ + + + Ansible Version + + { ansible_version } + + + { error ?
error
: ''} +
+ )} + ); } } diff --git a/src/components/DataListToolbar/DataListToolbar.jsx b/src/components/DataListToolbar/DataListToolbar.jsx index ba7ca9edc1..eb8b913911 100644 --- a/src/components/DataListToolbar/DataListToolbar.jsx +++ b/src/components/DataListToolbar/DataListToolbar.jsx @@ -1,4 +1,6 @@ import React from 'react'; +import { I18n } from '@lingui/react'; +import { Trans, t } from '@lingui/macro'; import { Button, Checkbox, @@ -112,122 +114,126 @@ class DataListToolbar extends React.Component { }; return ( -
- - - - - - - - - - -
- + {({ i18n }) => ( +
+ + + + + + + + + + +
+ + { searchColumnName } + + )} > - { searchColumnName } - - )} - > - {columns.filter(({ key }) => key !== searchKey).map(({ key, name }) => ( - - { name } - - ))} - - -