From c85342df741a960cd44a8f53a9a250be9e56d7f1 Mon Sep 17 00:00:00 2001 From: ismay Date: Thu, 7 May 2020 11:33:04 +0200 Subject: [PATCH] fix(widgets): add translated default texts --- .../has_default_button_label.feature | 5 +++ .../has_default_button_label/index.js | 9 ++++ .../has_default_placeholder.feature | 5 +++ .../has_default_placeholder/index.js | 9 ++++ .../has_default_button_label.feature | 5 +++ .../has_default_button_label/index.js | 9 ++++ .../has_default_placeholder.feature | 5 +++ .../has_default_placeholder/index.js | 9 ++++ .../has_default_remove_text.feature | 5 +++ .../has_default_remove_text/index.js | 9 ++++ .../has_default_clear_text.feature | 5 +++ .../has_default_clear_text/index.js | 9 ++++ .../has_default_empty_text.feature | 6 +++ .../has_default_empty_text/index.js | 13 ++++++ .../has_default_filter_nomatch_text.feature | 7 +++ .../has_default_filter_nomatch_text/index.js | 17 ++++++++ .../has_default_filter_placeholder.feature | 6 +++ .../has_default_filter_placeholder/index.js | 15 +++++++ .../has_default_loading_text.feature | 6 +++ .../has_default_loading_text/index.js | 13 ++++++ .../has_default_clear_text.feature | 5 +++ .../has_default_clear_text/index.js | 9 ++++ .../has_default_empty_text.feature | 6 +++ .../has_default_empty_text/index.js | 13 ++++++ .../has_default_filter_nomatch_text.feature | 7 +++ .../has_default_filter_nomatch_text/index.js | 17 ++++++++ .../has_default_filter_placeholder.feature | 6 +++ .../has_default_filter_placeholder/index.js | 15 +++++++ .../has_default_loading_text.feature | 6 +++ .../has_default_loading_text/index.js | 13 ++++++ packages/widgets/i18n/en.pot | 30 +++++++++++-- .../src/FileInputField/FileInputField.js | 23 ++++++---- .../FileInputField.stories.e2e.js | 20 +++++---- .../FileInputField/FileInputField.stories.js | 3 ++ .../FileInputFieldWithList.js | 42 ++++++++++-------- .../FileInputFieldWithList.stories.e2e.js | 10 +++++ .../FileInputFieldWithList.stories.js | 19 +++++--- .../src/MultiSelectField/MultiSelectField.js | 41 ++++++++++-------- .../MultiSelectField.stories.e2e.js | 12 ++++++ .../MultiSelectField.stories.js | 14 ++++++ .../SingleSelectField/SingleSelectField.js | 43 +++++++++++-------- .../SingleSelectField.stories.e2e.js | 12 ++++++ .../SingleSelectField.stories.js | 14 ++++++ .../src/translate/__tests__/index.test.js | 17 ++++++++ packages/widgets/src/translate/index.js | 19 ++++++++ 45 files changed, 504 insertions(+), 79 deletions(-) create mode 100644 cypress/integration/FileInputField/has_default_button_label.feature create mode 100644 cypress/integration/FileInputField/has_default_button_label/index.js create mode 100644 cypress/integration/FileInputField/has_default_placeholder.feature create mode 100644 cypress/integration/FileInputField/has_default_placeholder/index.js create mode 100644 cypress/integration/FileInputFieldWithList/has_default_button_label.feature create mode 100644 cypress/integration/FileInputFieldWithList/has_default_button_label/index.js create mode 100644 cypress/integration/FileInputFieldWithList/has_default_placeholder.feature create mode 100644 cypress/integration/FileInputFieldWithList/has_default_placeholder/index.js create mode 100644 cypress/integration/FileInputFieldWithList/has_default_remove_text.feature create mode 100644 cypress/integration/FileInputFieldWithList/has_default_remove_text/index.js create mode 100644 cypress/integration/MultiSelectField/has_default_clear_text.feature create mode 100644 cypress/integration/MultiSelectField/has_default_clear_text/index.js create mode 100644 cypress/integration/MultiSelectField/has_default_empty_text.feature create mode 100644 cypress/integration/MultiSelectField/has_default_empty_text/index.js create mode 100644 cypress/integration/MultiSelectField/has_default_filter_nomatch_text.feature create mode 100644 cypress/integration/MultiSelectField/has_default_filter_nomatch_text/index.js create mode 100644 cypress/integration/MultiSelectField/has_default_filter_placeholder.feature create mode 100644 cypress/integration/MultiSelectField/has_default_filter_placeholder/index.js create mode 100644 cypress/integration/MultiSelectField/has_default_loading_text.feature create mode 100644 cypress/integration/MultiSelectField/has_default_loading_text/index.js create mode 100644 cypress/integration/SingleSelectField/has_default_clear_text.feature create mode 100644 cypress/integration/SingleSelectField/has_default_clear_text/index.js create mode 100644 cypress/integration/SingleSelectField/has_default_empty_text.feature create mode 100644 cypress/integration/SingleSelectField/has_default_empty_text/index.js create mode 100644 cypress/integration/SingleSelectField/has_default_filter_nomatch_text.feature create mode 100644 cypress/integration/SingleSelectField/has_default_filter_nomatch_text/index.js create mode 100644 cypress/integration/SingleSelectField/has_default_filter_placeholder.feature create mode 100644 cypress/integration/SingleSelectField/has_default_filter_placeholder/index.js create mode 100644 cypress/integration/SingleSelectField/has_default_loading_text.feature create mode 100644 cypress/integration/SingleSelectField/has_default_loading_text/index.js create mode 100644 packages/widgets/src/translate/__tests__/index.test.js create mode 100644 packages/widgets/src/translate/index.js diff --git a/cypress/integration/FileInputField/has_default_button_label.feature b/cypress/integration/FileInputField/has_default_button_label.feature new file mode 100644 index 0000000000..ffcd460936 --- /dev/null +++ b/cypress/integration/FileInputField/has_default_button_label.feature @@ -0,0 +1,5 @@ +Feature: Button label for the FileInputField + + Scenario: Rendering a FileInputField + Given a default FileInputField is rendered + Then the default button label is visible diff --git a/cypress/integration/FileInputField/has_default_button_label/index.js b/cypress/integration/FileInputField/has_default_button_label/index.js new file mode 100644 index 0000000000..74f089078c --- /dev/null +++ b/cypress/integration/FileInputField/has_default_button_label/index.js @@ -0,0 +1,9 @@ +import { Given, Then } from 'cypress-cucumber-preprocessor/steps' + +Given('a default FileInputField is rendered', () => { + cy.visitStory('FileInputField', 'Default') +}) + +Then('the default button label is visible', () => { + cy.contains('Upload a file').should('be.visible') +}) diff --git a/cypress/integration/FileInputField/has_default_placeholder.feature b/cypress/integration/FileInputField/has_default_placeholder.feature new file mode 100644 index 0000000000..196dda7627 --- /dev/null +++ b/cypress/integration/FileInputField/has_default_placeholder.feature @@ -0,0 +1,5 @@ +Feature: Placeholder for the FileInputField + + Scenario: Rendering a FileInputField + Given a default FileInputField is rendered + Then the default placeholder is visible diff --git a/cypress/integration/FileInputField/has_default_placeholder/index.js b/cypress/integration/FileInputField/has_default_placeholder/index.js new file mode 100644 index 0000000000..479933862c --- /dev/null +++ b/cypress/integration/FileInputField/has_default_placeholder/index.js @@ -0,0 +1,9 @@ +import { Given, Then } from 'cypress-cucumber-preprocessor/steps' + +Given('a default FileInputField is rendered', () => { + cy.visitStory('FileInputField', 'Default') +}) + +Then('the default placeholder is visible', () => { + cy.contains('No file uploaded yet').should('be.visible') +}) diff --git a/cypress/integration/FileInputFieldWithList/has_default_button_label.feature b/cypress/integration/FileInputFieldWithList/has_default_button_label.feature new file mode 100644 index 0000000000..30be53a624 --- /dev/null +++ b/cypress/integration/FileInputFieldWithList/has_default_button_label.feature @@ -0,0 +1,5 @@ +Feature: Button label for the FileInputFieldWithList + + Scenario: Rendering a FileInputFieldWithList + Given a default FileInputFieldWithList is rendered + Then the default button label is visible diff --git a/cypress/integration/FileInputFieldWithList/has_default_button_label/index.js b/cypress/integration/FileInputFieldWithList/has_default_button_label/index.js new file mode 100644 index 0000000000..43fbbcaaa7 --- /dev/null +++ b/cypress/integration/FileInputFieldWithList/has_default_button_label/index.js @@ -0,0 +1,9 @@ +import { Given, Then } from 'cypress-cucumber-preprocessor/steps' + +Given('a default FileInputFieldWithList is rendered', () => { + cy.visitStory('FileInputFieldWithList', 'With default texts') +}) + +Then('the default button label is visible', () => { + cy.contains('Upload a file').should('be.visible') +}) diff --git a/cypress/integration/FileInputFieldWithList/has_default_placeholder.feature b/cypress/integration/FileInputFieldWithList/has_default_placeholder.feature new file mode 100644 index 0000000000..3cb31230f2 --- /dev/null +++ b/cypress/integration/FileInputFieldWithList/has_default_placeholder.feature @@ -0,0 +1,5 @@ +Feature: Placeholder for the FileInputFieldWithList + + Scenario: Rendering a FileInputFieldWithList + Given a default FileInputFieldWithList is rendered + Then the default placeholder is visible diff --git a/cypress/integration/FileInputFieldWithList/has_default_placeholder/index.js b/cypress/integration/FileInputFieldWithList/has_default_placeholder/index.js new file mode 100644 index 0000000000..d66afddd94 --- /dev/null +++ b/cypress/integration/FileInputFieldWithList/has_default_placeholder/index.js @@ -0,0 +1,9 @@ +import { Given, Then } from 'cypress-cucumber-preprocessor/steps' + +Given('a default FileInputFieldWithList is rendered', () => { + cy.visitStory('FileInputFieldWithList', 'With default texts') +}) + +Then('the default placeholder is visible', () => { + cy.contains('No file uploaded yet').should('be.visible') +}) diff --git a/cypress/integration/FileInputFieldWithList/has_default_remove_text.feature b/cypress/integration/FileInputFieldWithList/has_default_remove_text.feature new file mode 100644 index 0000000000..231627c5ff --- /dev/null +++ b/cypress/integration/FileInputFieldWithList/has_default_remove_text.feature @@ -0,0 +1,5 @@ +Feature: Placeholder for the FileInputFieldWithList + + Scenario: Rendering a FileInputFieldWithList + Given a default FileInputFieldWithList is rendered + Then the default remove text is visible diff --git a/cypress/integration/FileInputFieldWithList/has_default_remove_text/index.js b/cypress/integration/FileInputFieldWithList/has_default_remove_text/index.js new file mode 100644 index 0000000000..d4ec0da90e --- /dev/null +++ b/cypress/integration/FileInputFieldWithList/has_default_remove_text/index.js @@ -0,0 +1,9 @@ +import { Given, Then } from 'cypress-cucumber-preprocessor/steps' + +Given('a default FileInputFieldWithList is rendered', () => { + cy.visitStory('FileInputFieldWithList', 'With file and default texts') +}) + +Then('the default remove text is visible', () => { + cy.contains('Remove').should('be.visible') +}) diff --git a/cypress/integration/MultiSelectField/has_default_clear_text.feature b/cypress/integration/MultiSelectField/has_default_clear_text.feature new file mode 100644 index 0000000000..368887c0e4 --- /dev/null +++ b/cypress/integration/MultiSelectField/has_default_clear_text.feature @@ -0,0 +1,5 @@ +Feature: Clear text for the MultiSelectField + + Scenario: Rendering a clearable MultiSelectField + Given a clearable MultiSelectField with selected option is rendered + Then the clear text is visible diff --git a/cypress/integration/MultiSelectField/has_default_clear_text/index.js b/cypress/integration/MultiSelectField/has_default_clear_text/index.js new file mode 100644 index 0000000000..c166b76ca9 --- /dev/null +++ b/cypress/integration/MultiSelectField/has_default_clear_text/index.js @@ -0,0 +1,9 @@ +import { Given, Then } from 'cypress-cucumber-preprocessor/steps' + +Given('a clearable MultiSelectField with selected option is rendered', () => { + cy.visitStory('MultiSelectField', 'With clearable and selected option') +}) + +Then('the clear text is visible', () => { + cy.contains('Clear').should('be.visible') +}) diff --git a/cypress/integration/MultiSelectField/has_default_empty_text.feature b/cypress/integration/MultiSelectField/has_default_empty_text.feature new file mode 100644 index 0000000000..9fc50b7636 --- /dev/null +++ b/cypress/integration/MultiSelectField/has_default_empty_text.feature @@ -0,0 +1,6 @@ +Feature: Empty text for the MultiSelectField + + Scenario: Rendering an empty MultiSelectField + Given an empty MultiSelectField is rendered + When the Select is opened + Then the empty text is visible diff --git a/cypress/integration/MultiSelectField/has_default_empty_text/index.js b/cypress/integration/MultiSelectField/has_default_empty_text/index.js new file mode 100644 index 0000000000..6303e807a2 --- /dev/null +++ b/cypress/integration/MultiSelectField/has_default_empty_text/index.js @@ -0,0 +1,13 @@ +import { Given, Then, When } from 'cypress-cucumber-preprocessor/steps' + +Given('an empty MultiSelectField is rendered', () => { + cy.visitStory('MultiSelectField', 'Without options') +}) + +When('the Select is opened', () => { + cy.get('[data-test="dhis2-uicore-select-input"]').click() +}) + +Then('the empty text is visible', () => { + cy.contains('No data found').should('be.visible') +}) diff --git a/cypress/integration/MultiSelectField/has_default_filter_nomatch_text.feature b/cypress/integration/MultiSelectField/has_default_filter_nomatch_text.feature new file mode 100644 index 0000000000..935d0a3ded --- /dev/null +++ b/cypress/integration/MultiSelectField/has_default_filter_nomatch_text.feature @@ -0,0 +1,7 @@ +Feature: Nomatchtext for the MultiSelectField + + Scenario: Rendering a filterable MultiSelectField + Given a filterable MultiSelectField is rendered + When the Select is opened + And a filter that does not match any options is entered + Then the no match text is visible diff --git a/cypress/integration/MultiSelectField/has_default_filter_nomatch_text/index.js b/cypress/integration/MultiSelectField/has_default_filter_nomatch_text/index.js new file mode 100644 index 0000000000..b1bfcef13b --- /dev/null +++ b/cypress/integration/MultiSelectField/has_default_filter_nomatch_text/index.js @@ -0,0 +1,17 @@ +import { Given, Then, When } from 'cypress-cucumber-preprocessor/steps' + +Given('a filterable MultiSelectField is rendered', () => { + cy.visitStory('MultiSelectField', 'With filterable') +}) + +When('the Select is opened', () => { + cy.get('[data-test="dhis2-uicore-select-input"]').click() +}) + +When('a filter that does not match any options is entered', () => { + cy.focused().type('Two') +}) + +Then('the no match text is visible', () => { + cy.contains('No options found').should('be.visible') +}) diff --git a/cypress/integration/MultiSelectField/has_default_filter_placeholder.feature b/cypress/integration/MultiSelectField/has_default_filter_placeholder.feature new file mode 100644 index 0000000000..50182d6be4 --- /dev/null +++ b/cypress/integration/MultiSelectField/has_default_filter_placeholder.feature @@ -0,0 +1,6 @@ +Feature: Filter placeholder for the MultiSelectField + + Scenario: Rendering a filterable MultiSelectField + Given a filterable MultiSelectField is rendered + When the Select is opened + Then the filter placeholder exists diff --git a/cypress/integration/MultiSelectField/has_default_filter_placeholder/index.js b/cypress/integration/MultiSelectField/has_default_filter_placeholder/index.js new file mode 100644 index 0000000000..2fd35fba80 --- /dev/null +++ b/cypress/integration/MultiSelectField/has_default_filter_placeholder/index.js @@ -0,0 +1,15 @@ +import { Given, Then, When } from 'cypress-cucumber-preprocessor/steps' + +Given('a filterable MultiSelectField is rendered', () => { + cy.visitStory('MultiSelectField', 'With filterable') +}) + +When('the Select is opened', () => { + cy.get('[data-test="dhis2-uicore-select-input"]').click() +}) + +Then('the filter placeholder exists', () => { + cy.get( + '[data-test="dhis2-uicore-multiselect-filterinput"] [placeholder="Type to filter options"]' + ).should('exist') +}) diff --git a/cypress/integration/MultiSelectField/has_default_loading_text.feature b/cypress/integration/MultiSelectField/has_default_loading_text.feature new file mode 100644 index 0000000000..a6c8aa4c00 --- /dev/null +++ b/cypress/integration/MultiSelectField/has_default_loading_text.feature @@ -0,0 +1,6 @@ +Feature: Filter placeholder for the MultiSelectField + + Scenario: Rendering a filterable MultiSelectField + Given a loading MultiSelectField is rendered + When the Select is opened + Then the loading text is visible diff --git a/cypress/integration/MultiSelectField/has_default_loading_text/index.js b/cypress/integration/MultiSelectField/has_default_loading_text/index.js new file mode 100644 index 0000000000..79b32c0db6 --- /dev/null +++ b/cypress/integration/MultiSelectField/has_default_loading_text/index.js @@ -0,0 +1,13 @@ +import { Given, Then, When } from 'cypress-cucumber-preprocessor/steps' + +Given('a loading MultiSelectField is rendered', () => { + cy.visitStory('MultiSelectField', 'With loading') +}) + +When('the Select is opened', () => { + cy.get('[data-test="dhis2-uicore-select-input"]').click() +}) + +Then('the loading text is visible', () => { + cy.contains('Loading options').should('be.visible') +}) diff --git a/cypress/integration/SingleSelectField/has_default_clear_text.feature b/cypress/integration/SingleSelectField/has_default_clear_text.feature new file mode 100644 index 0000000000..30518cc930 --- /dev/null +++ b/cypress/integration/SingleSelectField/has_default_clear_text.feature @@ -0,0 +1,5 @@ +Feature: Clear text for the SingleSelectField + + Scenario: Rendering a clearable SingleSelectField + Given a clearable SingleSelectField with selected option is rendered + Then the clear text is visible diff --git a/cypress/integration/SingleSelectField/has_default_clear_text/index.js b/cypress/integration/SingleSelectField/has_default_clear_text/index.js new file mode 100644 index 0000000000..b5fb83fd06 --- /dev/null +++ b/cypress/integration/SingleSelectField/has_default_clear_text/index.js @@ -0,0 +1,9 @@ +import { Given, Then } from 'cypress-cucumber-preprocessor/steps' + +Given('a clearable SingleSelectField with selected option is rendered', () => { + cy.visitStory('SingleSelectField', 'With clearable and selected option') +}) + +Then('the clear text is visible', () => { + cy.contains('Clear').should('be.visible') +}) diff --git a/cypress/integration/SingleSelectField/has_default_empty_text.feature b/cypress/integration/SingleSelectField/has_default_empty_text.feature new file mode 100644 index 0000000000..e6e623af61 --- /dev/null +++ b/cypress/integration/SingleSelectField/has_default_empty_text.feature @@ -0,0 +1,6 @@ +Feature: Empty text for the SingleSelectField + + Scenario: Rendering an empty SingleSelectField + Given an empty SingleSelectField is rendered + When the Select is opened + Then the empty text is visible diff --git a/cypress/integration/SingleSelectField/has_default_empty_text/index.js b/cypress/integration/SingleSelectField/has_default_empty_text/index.js new file mode 100644 index 0000000000..1b56e9da9d --- /dev/null +++ b/cypress/integration/SingleSelectField/has_default_empty_text/index.js @@ -0,0 +1,13 @@ +import { Given, Then, When } from 'cypress-cucumber-preprocessor/steps' + +Given('an empty SingleSelectField is rendered', () => { + cy.visitStory('SingleSelectField', 'Without options') +}) + +When('the Select is opened', () => { + cy.get('[data-test="dhis2-uicore-select-input"]').click() +}) + +Then('the empty text is visible', () => { + cy.contains('No data found').should('be.visible') +}) diff --git a/cypress/integration/SingleSelectField/has_default_filter_nomatch_text.feature b/cypress/integration/SingleSelectField/has_default_filter_nomatch_text.feature new file mode 100644 index 0000000000..1738fd45bd --- /dev/null +++ b/cypress/integration/SingleSelectField/has_default_filter_nomatch_text.feature @@ -0,0 +1,7 @@ +Feature: Nomatchtext for the SingleSelectField + + Scenario: Rendering a filterable SingleSelectField + Given a filterable SingleSelectField is rendered + When the Select is opened + And a filter that does not match any options is entered + Then the no match text is visible diff --git a/cypress/integration/SingleSelectField/has_default_filter_nomatch_text/index.js b/cypress/integration/SingleSelectField/has_default_filter_nomatch_text/index.js new file mode 100644 index 0000000000..177205040e --- /dev/null +++ b/cypress/integration/SingleSelectField/has_default_filter_nomatch_text/index.js @@ -0,0 +1,17 @@ +import { Given, Then, When } from 'cypress-cucumber-preprocessor/steps' + +Given('a filterable SingleSelectField is rendered', () => { + cy.visitStory('SingleSelectField', 'With filterable') +}) + +When('the Select is opened', () => { + cy.get('[data-test="dhis2-uicore-select-input"]').click() +}) + +When('a filter that does not match any options is entered', () => { + cy.focused().type('Two') +}) + +Then('the no match text is visible', () => { + cy.contains('No options found').should('be.visible') +}) diff --git a/cypress/integration/SingleSelectField/has_default_filter_placeholder.feature b/cypress/integration/SingleSelectField/has_default_filter_placeholder.feature new file mode 100644 index 0000000000..db13d45cc8 --- /dev/null +++ b/cypress/integration/SingleSelectField/has_default_filter_placeholder.feature @@ -0,0 +1,6 @@ +Feature: Filter placeholder for the SingleSelectField + + Scenario: Rendering a filterable SingleSelectField + Given a filterable SingleSelectField is rendered + When the Select is opened + Then the filter placeholder exists diff --git a/cypress/integration/SingleSelectField/has_default_filter_placeholder/index.js b/cypress/integration/SingleSelectField/has_default_filter_placeholder/index.js new file mode 100644 index 0000000000..b843348fa3 --- /dev/null +++ b/cypress/integration/SingleSelectField/has_default_filter_placeholder/index.js @@ -0,0 +1,15 @@ +import { Given, Then, When } from 'cypress-cucumber-preprocessor/steps' + +Given('a filterable SingleSelectField is rendered', () => { + cy.visitStory('SingleSelectField', 'With filterable') +}) + +When('the Select is opened', () => { + cy.get('[data-test="dhis2-uicore-select-input"]').click() +}) + +Then('the filter placeholder exists', () => { + cy.get( + '[data-test="dhis2-uicore-singleselect-filterinput"] [placeholder="Type to filter options"]' + ).should('exist') +}) diff --git a/cypress/integration/SingleSelectField/has_default_loading_text.feature b/cypress/integration/SingleSelectField/has_default_loading_text.feature new file mode 100644 index 0000000000..3a8167a3f0 --- /dev/null +++ b/cypress/integration/SingleSelectField/has_default_loading_text.feature @@ -0,0 +1,6 @@ +Feature: Filter placeholder for the SingleSelectField + + Scenario: Rendering a filterable SingleSelectField + Given a loading SingleSelectField is rendered + When the Select is opened + Then the loading text is visible diff --git a/cypress/integration/SingleSelectField/has_default_loading_text/index.js b/cypress/integration/SingleSelectField/has_default_loading_text/index.js new file mode 100644 index 0000000000..faef236e2c --- /dev/null +++ b/cypress/integration/SingleSelectField/has_default_loading_text/index.js @@ -0,0 +1,13 @@ +import { Given, Then, When } from 'cypress-cucumber-preprocessor/steps' + +Given('a loading SingleSelectField is rendered', () => { + cy.visitStory('SingleSelectField', 'With loading') +}) + +When('the Select is opened', () => { + cy.get('[data-test="dhis2-uicore-select-input"]').click() +}) + +Then('the loading text is visible', () => { + cy.contains('Loading options').should('be.visible') +}) diff --git a/packages/widgets/i18n/en.pot b/packages/widgets/i18n/en.pot index f73e0f6e06..8f67f27cc7 100644 --- a/packages/widgets/i18n/en.pot +++ b/packages/widgets/i18n/en.pot @@ -5,8 +5,17 @@ msgstr "" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" -"POT-Creation-Date: 2020-02-18T13:19:29.126Z\n" -"PO-Revision-Date: 2020-02-18T13:19:29.126Z\n" +"POT-Creation-Date: 2020-05-14T13:50:41.269Z\n" +"PO-Revision-Date: 2020-05-14T13:50:41.269Z\n" + +msgid "Upload a file" +msgstr "" + +msgid "No file uploaded yet" +msgstr "" + +msgid "Remove" +msgstr "" msgid "Search apps" msgstr "" @@ -29,5 +38,20 @@ msgstr "" msgid "Logout" msgstr "" -msgid "Something went wrong with loading the children." +msgid "Clear" +msgstr "" + +msgid "No data found" +msgstr "" + +msgid "Type to filter options" +msgstr "" + +msgid "Loading options" +msgstr "" + +msgid "No options found" +msgstr "" + +msgid "Could not load children" msgstr "" diff --git a/packages/widgets/src/FileInputField/FileInputField.js b/packages/widgets/src/FileInputField/FileInputField.js index 645405fc8a..cec5c40de6 100644 --- a/packages/widgets/src/FileInputField/FileInputField.js +++ b/packages/widgets/src/FileInputField/FileInputField.js @@ -1,5 +1,6 @@ import React from 'react' import propTypes from '@dhis2/prop-types' +import i18n from '@dhis2/d2-i18n' import { sharedPropTypes } from '@dhis2/ui-constants' @@ -10,6 +11,7 @@ import { Field, Label, } from '@dhis2/ui-core' +import translate from '../translate' /** * @module @@ -63,7 +65,7 @@ const FileInputField = ({ - {!children && placeholder ? ( - {placeholder} - ) : ( + {children ? ( children + ) : ( + + {translate(placeholder)} + )} @@ -93,6 +97,9 @@ const FileInputField = ({ FileInputField.defaultProps = { accept: '*', dataTest: 'dhis2-uiwidgets-fileinputfield', + + buttonLabel: () => i18n.t('Upload a file'), + placeholder: () => i18n.t('No file uploaded yet'), } /** @@ -104,9 +111,9 @@ FileInputField.defaultProps = { * @prop {function} [onBlur] * @prop {function} [onFocus] * @prop {string} [label] - * @prop {string} [buttonLabel] + * @prop {string|function} [buttonLabel] * @prop {string} [className] - * @prop {string} [placeholder] + * @prop {string|function} [placeholder] * @prop {string} [tabIndex] * * @prop {boolean} [required] @@ -130,7 +137,7 @@ FileInputField.defaultProps = { */ FileInputField.propTypes = { accept: propTypes.string, - buttonLabel: propTypes.string, + buttonLabel: propTypes.oneOfType([propTypes.string, propTypes.func]), children: propTypes.node, className: propTypes.string, dataTest: propTypes.string, @@ -142,7 +149,7 @@ FileInputField.propTypes = { large: sharedPropTypes.sizePropType, multiple: propTypes.bool, name: propTypes.string, - placeholder: propTypes.string, + placeholder: propTypes.oneOfType([propTypes.string, propTypes.func]), required: propTypes.bool, small: sharedPropTypes.sizePropType, tabIndex: propTypes.string, diff --git a/packages/widgets/src/FileInputField/FileInputField.stories.e2e.js b/packages/widgets/src/FileInputField/FileInputField.stories.e2e.js index 63b06e2233..506fd05eb8 100644 --- a/packages/widgets/src/FileInputField/FileInputField.stories.e2e.js +++ b/packages/widgets/src/FileInputField/FileInputField.stories.e2e.js @@ -2,11 +2,15 @@ import React from 'react' import { storiesOf } from '@storybook/react' import { FileInputField } from './FileInputField.js' -storiesOf('FileInputField', module).add('With label and required', () => ( - -)) +storiesOf('FileInputField', module) + .add('With label and required', () => ( + + )) + .add('Default', () => ( + + )) diff --git a/packages/widgets/src/FileInputField/FileInputField.stories.js b/packages/widgets/src/FileInputField/FileInputField.stories.js index 6a250c6724..f3b6db1504 100644 --- a/packages/widgets/src/FileInputField/FileInputField.stories.js +++ b/packages/widgets/src/FileInputField/FileInputField.stories.js @@ -207,3 +207,6 @@ storiesOf('Components/Widgets/FileInputField', module) name="upload" /> )) + .add('Default: buttonLabel and placeholder', () => ( + + )) diff --git a/packages/widgets/src/FileInputFieldWithList/FileInputFieldWithList.js b/packages/widgets/src/FileInputFieldWithList/FileInputFieldWithList.js index f106886a17..5dc08e3990 100644 --- a/packages/widgets/src/FileInputFieldWithList/FileInputFieldWithList.js +++ b/packages/widgets/src/FileInputFieldWithList/FileInputFieldWithList.js @@ -1,10 +1,11 @@ import React, { Component } from 'react' import propTypes from '@dhis2/prop-types' import { sharedPropTypes } from '@dhis2/ui-constants' +import i18n from '@dhis2/d2-i18n' import { FileInputField } from '../FileInputField/FileInputField.js' - import { FileListItemWithRemove } from './FileListItemWithRemove.js' +import translate from '../translate' /** * @module @@ -92,7 +93,7 @@ class FileInputFieldWithList extends Component { return ( = 1)} @@ -106,7 +107,7 @@ class FileInputFieldWithList extends Component { onBlur={onBlur} onChange={this.handleChange} onFocus={onFocus} - placeholder={placeholder} + placeholder={translate(placeholder)} required={required} small={small} tabIndex={tabIndex} @@ -114,15 +115,16 @@ class FileInputFieldWithList extends Component { validationText={validationText} warning={warning} > - {files.map(file => ( - - ))} + {files.length > 0 && + files.map(file => ( + + ))} ) } @@ -131,22 +133,26 @@ class FileInputFieldWithList extends Component { FileInputFieldWithList.defaultProps = { dataTest: 'dhis2-uiwidgets-fileinputfieldwithlist', files: [], + + buttonLabel: () => i18n.t('Upload a file'), + placeholder: () => i18n.t('No file uploaded yet'), + removeText: () => i18n.t('Remove'), } /** * @typedef {Object} PropTypes * @static * - * @prop {string} [removeText] + * @prop {string|function} [removeText] * @prop {function} onChange * @prop {Array} [files=[]] - an array of File instances (NOTE: not a FileList instance) * @prop {string} [name] * @prop {function} [onBlur] * @prop {function} [onFocus] * @prop {string} [label] - * @prop {string} [buttonLabel] + * @prop {string|function} [buttonLabel] * @prop {string} [className] - * @prop {string} [placeholder] + * @prop {string|function} [placeholder] * @prop {string} [tabIndex] * * @prop {boolean} [required] @@ -171,7 +177,7 @@ FileInputFieldWithList.defaultProps = { FileInputFieldWithList.propTypes = { onChange: propTypes.func.isRequired, accept: propTypes.string, - buttonLabel: propTypes.string, + buttonLabel: propTypes.oneOfType([propTypes.string, propTypes.func]), className: propTypes.string, dataTest: propTypes.string, disabled: propTypes.bool, @@ -183,8 +189,8 @@ FileInputFieldWithList.propTypes = { large: sharedPropTypes.sizePropType, multiple: propTypes.bool, name: propTypes.string, - placeholder: propTypes.string, - removeText: propTypes.string, + placeholder: propTypes.oneOfType([propTypes.string, propTypes.func]), + removeText: propTypes.oneOfType([propTypes.string, propTypes.func]), required: propTypes.bool, small: sharedPropTypes.sizePropType, tabIndex: propTypes.string, diff --git a/packages/widgets/src/FileInputFieldWithList/FileInputFieldWithList.stories.e2e.js b/packages/widgets/src/FileInputFieldWithList/FileInputFieldWithList.stories.e2e.js index 5767afba1d..54153d4636 100644 --- a/packages/widgets/src/FileInputFieldWithList/FileInputFieldWithList.stories.e2e.js +++ b/packages/widgets/src/FileInputFieldWithList/FileInputFieldWithList.stories.e2e.js @@ -62,3 +62,13 @@ storiesOf('FileInputFieldWithList', module) onChange={onChange} /> )) + .add('With file and default texts', () => ( + + )) + .add('With default texts', () => ( + + )) diff --git a/packages/widgets/src/FileInputFieldWithList/FileInputFieldWithList.stories.js b/packages/widgets/src/FileInputFieldWithList/FileInputFieldWithList.stories.js index 1eed3805c8..aa29bf4c1a 100644 --- a/packages/widgets/src/FileInputFieldWithList/FileInputFieldWithList.stories.js +++ b/packages/widgets/src/FileInputFieldWithList/FileInputFieldWithList.stories.js @@ -10,9 +10,8 @@ const onChange = ({ files }) => { console.log('files: ', files) } -storiesOf('Components/Widgets/FileInputFieldWithList', module).add( - 'Default', - () => ( +storiesOf('Components/Widgets/FileInputFieldWithList', module) + .add('Default', () => ( - ) -) + )) + .add('Default: buttonLabel and removeText', () => ( + + )) + .add('Default: placeholder', () => ( + + )) diff --git a/packages/widgets/src/MultiSelectField/MultiSelectField.js b/packages/widgets/src/MultiSelectField/MultiSelectField.js index 322a82c160..ab7197216e 100644 --- a/packages/widgets/src/MultiSelectField/MultiSelectField.js +++ b/packages/widgets/src/MultiSelectField/MultiSelectField.js @@ -1,8 +1,10 @@ import propTypes from '@dhis2/prop-types' import React from 'react' +import i18n from '@dhis2/d2-i18n' import { sharedPropTypes } from '@dhis2/ui-constants' import { Field, Box, MultiSelect } from '@dhis2/ui-core' +import translate from '../translate' /** * @module @@ -80,14 +82,14 @@ class MultiSelectField extends React.Component { valid={valid} disabled={disabled} clearable={clearable} - clearText={clearText} + clearText={translate(clearText)} filterable={filterable} - filterPlaceholder={filterPlaceholder} + filterPlaceholder={translate(filterPlaceholder)} placeholder={placeholder} prefix={prefix} - empty={empty} - loadingText={loadingText} - noMatchText={noMatchText} + empty={translate(empty)} + loadingText={translate(loadingText)} + noMatchText={translate(noMatchText)} initialFocus={initialFocus} dense={dense} > @@ -102,6 +104,12 @@ class MultiSelectField extends React.Component { MultiSelectField.defaultProps = { selected: [], dataTest: 'dhis2-uiwidgets-multiselectfield', + + clearText: () => i18n.t('Clear'), + empty: () => i18n.t('No data found'), + filterPlaceholder: () => i18n.t('Type to filter options'), + loadingText: () => i18n.t('Loading options'), + noMatchText: () => i18n.t('No options found'), } /** @@ -126,16 +134,16 @@ MultiSelectField.defaultProps = { * @prop {boolean} [initialFocus] * @prop {string} [validationText] * @prop {string} [helpText] - * @prop {string} [clearText] - Only required if clearable is true + * @prop {string|function} [clearText] * @prop {boolean} [clearable] - * @prop {Node} [empty] - * @prop {string} [filterPlaceholder] + * @prop {Node|function} [empty] + * @prop {string|function} [filterPlaceholder] * @prop {boolean} [filterable] - * @prop {string} [loadingText] + * @prop {string|function} [loadingText] * @prop {string} [maxHeight] * @prop {string} [inputMaxHeight] * @prop {string} [inputWidth] - * @prop {string} [noMatchText] - Only required if filterable is true + * @prop {string|function} [noMatchText] * @prop {string} [placeholder] * @prop {string} [prefix] * @prop {string} [dataTest] @@ -143,14 +151,14 @@ MultiSelectField.defaultProps = { MultiSelectField.propTypes = { children: propTypes.node, className: propTypes.string, - clearText: propTypes.requiredIf(props => props.clearable, propTypes.string), + clearText: propTypes.oneOfType([propTypes.string, propTypes.func]), clearable: propTypes.bool, dataTest: propTypes.string, dense: propTypes.bool, disabled: propTypes.bool, - empty: propTypes.node, + empty: propTypes.oneOfType([propTypes.node, propTypes.func]), error: sharedPropTypes.statusPropType, - filterPlaceholder: propTypes.string, + filterPlaceholder: propTypes.oneOfType([propTypes.node, propTypes.func]), filterable: propTypes.bool, helpText: propTypes.string, initialFocus: propTypes.bool, @@ -158,12 +166,9 @@ MultiSelectField.propTypes = { inputWidth: propTypes.string, label: propTypes.string, loading: propTypes.bool, - loadingText: propTypes.string, + loadingText: propTypes.oneOfType([propTypes.string, propTypes.func]), maxHeight: propTypes.string, - noMatchText: propTypes.requiredIf( - props => props.filterable, - propTypes.string - ), + noMatchText: propTypes.oneOfType([propTypes.string, propTypes.func]), placeholder: propTypes.string, prefix: propTypes.string, required: propTypes.bool, diff --git a/packages/widgets/src/MultiSelectField/MultiSelectField.stories.e2e.js b/packages/widgets/src/MultiSelectField/MultiSelectField.stories.e2e.js index 3be1a95c07..6f7f013773 100644 --- a/packages/widgets/src/MultiSelectField/MultiSelectField.stories.e2e.js +++ b/packages/widgets/src/MultiSelectField/MultiSelectField.stories.e2e.js @@ -34,3 +34,15 @@ storiesOf('MultiSelectField', module) )) + .add('With clearable and selected option', () => ( + + + + )) + .add('With filterable', () => ( + + + + )) + .add('With loading', () => ) + .add('Without options', () => ) diff --git a/packages/widgets/src/MultiSelectField/MultiSelectField.stories.js b/packages/widgets/src/MultiSelectField/MultiSelectField.stories.js index c93b6a0863..29cca0b4c8 100644 --- a/packages/widgets/src/MultiSelectField/MultiSelectField.stories.js +++ b/packages/widgets/src/MultiSelectField/MultiSelectField.stories.js @@ -79,3 +79,17 @@ storiesOf('Components/Widgets/MultiSelectField', module) {options} )) + .add('Default: clearText', () => ( + + + + )) + .add('Default: filterPlaceholder and noMatchText', () => ( + + )) + .add('Default: loadingText', () => ) + .add('Default: empty', () => ) diff --git a/packages/widgets/src/SingleSelectField/SingleSelectField.js b/packages/widgets/src/SingleSelectField/SingleSelectField.js index e6681fb66e..8e752b0525 100644 --- a/packages/widgets/src/SingleSelectField/SingleSelectField.js +++ b/packages/widgets/src/SingleSelectField/SingleSelectField.js @@ -1,8 +1,10 @@ import React from 'react' +import i18n from '@dhis2/d2-i18n' import propTypes from '@dhis2/prop-types' import { Field, SingleSelect, Box } from '@dhis2/ui-core' import { sharedPropTypes } from '@dhis2/ui-constants' +import translate from '../translate' /** * @module @@ -80,14 +82,14 @@ class SingleSelectField extends React.Component { valid={valid} disabled={disabled} clearable={clearable} - clearText={clearText} + clearText={translate(clearText)} filterable={filterable} - filterPlaceholder={filterPlaceholder} + filterPlaceholder={translate(filterPlaceholder)} placeholder={placeholder} prefix={prefix} - empty={empty} - loadingText={loadingText} - noMatchText={noMatchText} + empty={translate(empty)} + loadingText={translate(loadingText)} + noMatchText={translate(noMatchText)} initialFocus={initialFocus} dense={dense} > @@ -100,8 +102,14 @@ class SingleSelectField extends React.Component { } SingleSelectField.defaultProps = { - selected: '', dataTest: 'dhis2-uiwidgets-singleselectfield', + selected: '', + + clearText: () => i18n.t('Clear'), + empty: () => i18n.t('No data found'), + filterPlaceholder: () => i18n.t('Type to filter options'), + loadingText: () => i18n.t('Loading options'), + noMatchText: () => i18n.t('No options found'), } /** @@ -126,16 +134,16 @@ SingleSelectField.defaultProps = { * @prop {boolean} [initialFocus] * @prop {string} [validationText] * @prop {string} [helpText] - * @prop {string} [clearText] - Only required if clearable is true + * @prop {string|function} [clearText] * @prop {boolean} [clearable] - * @prop {Node} [empty] - * @prop {string} [filterPlaceholder] + * @prop {Node|function} [empty] + * @prop {string|function} [filterPlaceholder] * @prop {boolean} [filterable] - * @prop {string} [loadingText] + * @prop {string|function} [loadingText] * @prop {string} [maxHeight] * @prop {string} [inputMaxHeight] * @prop {string} [inputWidth] - * @prop {string} [noMatchText] - Only required if filterable is true + * @prop {string|function} [noMatchText] * @prop {string} [placeholder] * @prop {string} [prefix] * @prop {string} [dataTest] @@ -143,14 +151,14 @@ SingleSelectField.defaultProps = { SingleSelectField.propTypes = { children: propTypes.node, className: propTypes.string, - clearText: propTypes.requiredIf(props => props.clearable, propTypes.string), + clearText: propTypes.oneOfType([propTypes.string, propTypes.func]), clearable: propTypes.bool, dataTest: propTypes.string, dense: propTypes.bool, disabled: propTypes.bool, - empty: propTypes.node, + empty: propTypes.oneOfType([propTypes.node, propTypes.func]), error: sharedPropTypes.statusPropType, - filterPlaceholder: propTypes.string, + filterPlaceholder: propTypes.oneOfType([propTypes.node, propTypes.func]), filterable: propTypes.bool, helpText: propTypes.string, initialFocus: propTypes.bool, @@ -158,12 +166,9 @@ SingleSelectField.propTypes = { inputWidth: propTypes.string, label: propTypes.string, loading: propTypes.bool, - loadingText: propTypes.string, + loadingText: propTypes.oneOfType([propTypes.string, propTypes.func]), maxHeight: propTypes.string, - noMatchText: propTypes.requiredIf( - props => props.filterable, - propTypes.string - ), + noMatchText: propTypes.oneOfType([propTypes.string, propTypes.func]), placeholder: propTypes.string, prefix: propTypes.string, required: propTypes.bool, diff --git a/packages/widgets/src/SingleSelectField/SingleSelectField.stories.e2e.js b/packages/widgets/src/SingleSelectField/SingleSelectField.stories.e2e.js index 9513ecaab6..d33814cb2a 100644 --- a/packages/widgets/src/SingleSelectField/SingleSelectField.stories.e2e.js +++ b/packages/widgets/src/SingleSelectField/SingleSelectField.stories.e2e.js @@ -34,3 +34,15 @@ storiesOf('SingleSelectField', module) )) + .add('With clearable and selected option', () => ( + + + + )) + .add('With filterable', () => ( + + + + )) + .add('With loading', () => ) + .add('Without options', () => ) diff --git a/packages/widgets/src/SingleSelectField/SingleSelectField.stories.js b/packages/widgets/src/SingleSelectField/SingleSelectField.stories.js index 1cd09885ec..fc1b73b7c8 100644 --- a/packages/widgets/src/SingleSelectField/SingleSelectField.stories.js +++ b/packages/widgets/src/SingleSelectField/SingleSelectField.stories.js @@ -78,3 +78,17 @@ storiesOf('Components/Widgets/SingleSelectField', module) {options} )) + .add('Default: clearText', () => ( + + + + )) + .add('Default: filterPlaceholder and noMatchText', () => ( + + )) + .add('Default: loadingText', () => ) + .add('Default: empty', () => ) diff --git a/packages/widgets/src/translate/__tests__/index.test.js b/packages/widgets/src/translate/__tests__/index.test.js new file mode 100644 index 0000000000..a58a8cb385 --- /dev/null +++ b/packages/widgets/src/translate/__tests__/index.test.js @@ -0,0 +1,17 @@ +import translate from '../index.js' + +describe('translate', () => { + it('should call prop and return the result if it is a function', () => { + const spy = jest.fn(() => 'translated string') + const result = translate(spy) + + expect(spy).toHaveBeenCalled() + expect(result).toBe('translated string') + }) + + it('should return prop as is if it is not a function', () => { + const result = translate('just a string') + + expect(result).toBe('just a string') + }) +}) diff --git a/packages/widgets/src/translate/index.js b/packages/widgets/src/translate/index.js new file mode 100644 index 0000000000..fa5b9a46e7 --- /dev/null +++ b/packages/widgets/src/translate/index.js @@ -0,0 +1,19 @@ +/* + * This allows us to delay calling i18n.t until after the + * language has been set. Otherwise the translations could + * potentially use the wrong language. + * + * It checks if the passed prop is a function. If so, + * it'll execute it. Since this should only be called during + * render, we can be certain that i18n will have initialized. + */ + +const translate = prop => { + if (typeof prop === 'function') { + return prop() + } + + return prop +} + +export default translate