From 6e1a14877ef06d27f6a18c1d37708a00884aeb4a Mon Sep 17 00:00:00 2001 From: Pavlov Viacheslav Date: Fri, 19 Oct 2018 17:58:33 +0300 Subject: [PATCH] i18n - src/translations.json for application strings - translations for common components - translations split into modules, a script compiles one translation file - i18n for user module - i18n for requests module - i18n for list module - i18n for accessions module - i18n for repository module - i18n for subsets - i18n for institutes module - i18n for crop module --- i18n/generateI18n.ts | 17 + locales/en/common.json | 61 +- locales/en/translations.json | 925 +++++++++++++----- package-lock.json | 217 ++-- package.json | 8 +- src/accessions/translations.json | 164 ++++ src/accessions/ui/BrowsePage.tsx | 21 +- src/accessions/ui/DisplayPage.tsx | 88 +- src/accessions/ui/MapPage.tsx | 14 +- src/accessions/ui/OverviewPage.tsx | 38 +- src/accessions/ui/c/AccessionCard.tsx | 9 +- src/accessions/ui/c/Filters.tsx | 54 +- src/accessions/ui/c/PdciTable.tsx | 4 +- src/actions/serverInfo.ts | 2 +- src/cms/translations.json | 15 + src/cms/ui/c/MenuStepper.tsx | 2 +- src/crop/translations.json | 50 + src/crop/ui/BrowsePage.tsx | 12 +- src/crop/ui/DisplayPage.tsx | 14 +- src/crop/ui/EditPage.tsx | 18 +- src/crop/ui/c/CropCard.tsx | 10 +- src/crop/ui/c/CropForm.tsx | 23 +- src/crop/ui/c/CropSelector.tsx | 2 +- src/institutes/translations.json | 46 + src/institutes/ui/BrowsePage.tsx | 11 +- src/institutes/ui/DisplayPage.tsx | 36 +- "src/institutes/ui/\321\201/Filters.tsx" | 21 +- .../institutes/ui/\321\201/InstituteCard.tsx" | 8 +- src/list/translations.json | 15 + src/list/ui/BrowsePage.tsx | 15 +- src/model/accession/Accession.ts | 60 +- src/model/genesys/FaoInstitute.ts | 2 +- src/model/request/RequestInfo.ts | 4 +- src/model/user/User.ts | 12 +- src/repository/translations.json | 59 ++ src/repository/ui/CreateFolderDialog.tsx | 6 +- src/repository/ui/EditFilePage.tsx | 4 +- src/repository/ui/ImageGalleryPage.tsx | 15 +- src/repository/ui/RepositoryBrowser.tsx | 20 +- src/repository/ui/UpdateFolderDialog.tsx | 4 +- src/repository/ui/c/FileCard.tsx | 17 +- src/repository/ui/c/FileForm.tsx | 31 +- src/repository/ui/c/FolderCard.tsx | 6 +- src/repository/ui/c/FolderCrumbs.tsx | 9 +- src/repository/ui/c/FolderForm.tsx | 15 +- src/repository/ui/c/ImageGalleryView.tsx | 6 +- src/requests/translations.json | 65 ++ src/requests/ui/admin/BrowsePage.tsx | 7 +- src/requests/ui/admin/DisplayPage.tsx | 58 +- src/requests/ui/admin/c/RequestCard.tsx | 9 +- src/requests/ui/request-stepper/steps.ts | 6 +- .../steps/accessionsList/AccessionsList.tsx | 7 +- .../request-stepper/steps/confirm/index.tsx | 2 +- .../requestInfo/c/PurposeTypeRadioGroup.tsx | 9 +- .../steps/requestInfo/c/RequestInfoForm.tsx | 19 +- src/subsets/translations.json | 113 +++ src/subsets/ui/BrowsePage.tsx | 11 +- src/subsets/ui/DisplayPage.tsx | 14 +- src/subsets/ui/c/Filters.tsx | 14 +- src/subsets/ui/c/SubsetCard.tsx | 15 +- src/subsets/ui/c/SubsetDisplay.tsx | 6 +- src/subsets/ui/dashboard/DashboardPage.tsx | 12 +- .../ui/dashboard/subset-stepper/steps.ts | 8 +- .../accessions-list/ListOfAccessions.tsx | 41 +- .../steps/basic-info/BasicInfoForm.tsx | 17 +- .../subset-stepper/steps/basic-info/index.tsx | 6 +- .../steps/creators/SubsetCreatorForm.tsx | 39 +- src/translations.json | 168 ++++ .../catalog/accession/AccessionRefsTable.tsx | 16 +- src/ui/common/ItemsEditor.tsx | 15 +- src/ui/common/Menu.tsx | 8 +- src/ui/common/Properties.tsx | 8 +- src/ui/common/PropertiesCard.tsx | 2 +- src/ui/common/Tabs.tsx | 7 +- src/ui/common/buttons/ActionButton.tsx | 8 +- src/ui/common/buttons/BackButton.tsx | 8 +- src/ui/common/buttons/UploadButton.tsx | 8 +- src/ui/common/checkbox/index.tsx | 7 +- .../csv-configuration/CSVConfiguration.tsx | 34 +- src/ui/common/file-uploader/TargetBox.tsx | 12 +- src/ui/common/filter/BooleanFilter.tsx | 18 +- .../filter/CollapsibleComponentSearch.tsx | 8 +- src/ui/common/filter/DateFilter.tsx | 16 +- .../common/filter/ExpandFiltersComponent.tsx | 8 +- src/ui/common/filter/FiltersBlock.tsx | 9 +- src/ui/common/filter/NumberFilter.tsx | 20 +- src/ui/common/filter/PrettyFilters.tsx | 8 +- src/ui/common/filter/StringArrFilter.tsx | 2 +- src/ui/common/filter/StringFilter.tsx | 10 +- src/ui/common/filter/TextFilter.tsx | 14 +- src/ui/common/forms/FormControl.tsx | 8 +- src/ui/common/forms/Toggle.tsx | 7 +- src/ui/common/heading/ContentHeader.tsx | 21 +- .../heading/ContentHeaderWithButton.tsx | 8 +- src/ui/common/layout/Section.tsx | 7 +- src/ui/common/not-found/index.tsx | 4 +- src/ui/common/pagination/index.tsx | 6 +- src/ui/common/pie-chart/index.tsx | 8 +- src/ui/common/snackbar/Snackbar.tsx | 10 +- src/ui/common/stepper/StepNavigation.tsx | 24 +- src/ui/common/stepper/StepperTemplate.tsx | 5 +- src/ui/common/stepper/progress-menu/index.tsx | 10 +- src/ui/common/tables/MyDataTable.tsx | 17 +- src/ui/common/time/McpdDate.tsx | 7 +- src/ui/common/time/PrettyDate.tsx | 10 +- src/ui/genesys/LicenseSelector.tsx | 7 +- src/ui/layout/DashboardLayout.tsx | 21 +- src/ui/layout/Footer/index.tsx | 20 +- src/ui/layout/Header/LeftMenu.tsx | 10 +- src/ui/layout/Header/UserLoginMenu.tsx | 4 +- src/ui/layout/Header/UserMenuComponent.tsx | 4 +- src/ui/layout/Header/index.tsx | 11 +- src/ui/layout/PageLayout.tsx | 13 +- src/ui/pages/_base/StepperPage.tsx | 7 +- src/ui/pages/welcome/index.tsx | 32 +- src/user/translations.json | 115 +++ src/user/ui/LoginPage.tsx | 9 +- src/user/ui/RegistrationPage.tsx | 10 +- src/user/ui/admin/BrowsePage.tsx | 2 +- src/user/ui/admin/DisplayPage.tsx | 18 +- src/user/ui/admin/EditUserPage.tsx | 2 +- src/user/ui/admin/c/UserCard.tsx | 11 +- src/user/ui/admin/c/UserFilter.tsx | 18 +- src/user/ui/admin/c/UserForm.tsx | 22 +- src/user/ui/c/LoginForm.tsx | 14 +- src/user/ui/c/RegistrationForm.tsx | 18 +- src/user/ui/c/UserProfileCard.tsx | 25 +- src/user/ui/dashboard/ChangePasswordPage.tsx | 4 +- src/user/ui/dashboard/ProfilePage.tsx | 2 +- src/user/ui/dashboard/c/PasswordForm.tsx | 8 +- 130 files changed, 2495 insertions(+), 1146 deletions(-) create mode 100644 i18n/generateI18n.ts create mode 100644 src/accessions/translations.json create mode 100644 src/cms/translations.json create mode 100644 src/crop/translations.json create mode 100644 src/institutes/translations.json create mode 100644 src/list/translations.json create mode 100644 src/repository/translations.json create mode 100644 src/requests/translations.json create mode 100644 src/subsets/translations.json create mode 100644 src/translations.json create mode 100644 src/user/translations.json diff --git a/i18n/generateI18n.ts b/i18n/generateI18n.ts new file mode 100644 index 00000000..92397b8a --- /dev/null +++ b/i18n/generateI18n.ts @@ -0,0 +1,17 @@ +const fg = require('fast-glob'); +const _ = require('lodash'); +const fs = require('fs'); + + +fg([`./src/**/translations.json`, `./src/translations.json`]) + .then((entries) => entries.map((path) => getTranslations(path))) + .then((content) => fs.writeFileSync(`locales/en/translations.json`, `{\n${content}}`)); + + +const getTranslations = (path) => { + const prefix = path.substring(path.indexOf('./src/') + './src/'.length, path.indexOf('/translations.json')); + console.log('Loading translations of module', prefix); + const fileContent = fs.readFileSync(path, 'utf8'); + + return prefix !== '/' ? _(`"${prefix}": ${fileContent}\n`).value() : fileContent.substr(1, fileContent.length - 2); +}; diff --git a/locales/en/common.json b/locales/en/common.json index d7595995..27787784 100644 --- a/locales/en/common.json +++ b/locales/en/common.json @@ -1,24 +1,65 @@ { "action": { "add": "Add {{what, lowercase}}", + "applyFilters": "Apply filters", + "approve": "Approve and publish", + "back": "Back", "backTo": "Back to {{where, lowercase}}", "cancel": "Cancel", "delete": "Delete", + "deleteData": "Delete data", "edit": "Edit", - "login": "Login", "logout": "Logout", + "nextStep": "Next step", + "reject": "Reject", + "remove": "Remove", + "reset": "Reset", + "return": "Return", + "save": "Save", + "saveChanges": "Save changes", "search": "Search", - "viewDetails": "View details" + "sendToReview": "Send to review", + "unpublish": "Unpublish" }, - "label": { - "item": "Item", - "item_plural": "Items", - "list": "List", - "list_plural": "Lists", - "prettyNumber": "{{value, number}}" + "csv": { + "autoDetect": "Auto-detect ", + "autoDetectLabel": "Auto-detect CSV settings", + "comma": "Comma", + "configuration": "CSV configuration", + "escapeCharacter": "Escape character", + "other": "Other", + "quoteCharacter": "Quote character", + "semicolon": "Semicolon", + "separator": "Separator character", + "space": "Space", + "tab": "Tab", + "typeYourEscapeCharacter": "Type your escape character", + "typeYourQuoteCharacter": "Type your quote character", + "typeYourSeparator": "Type your separator" + }, + "f": { + "dateSearch": "Date search", + "fromIncluding": "From including", + "lastModifiedDate": "Last modified date", + "textSearch": "Text search" }, - "message": { - "confirmDelete": "Deleting the {{what, lowercase}} record is only possible when there is no associated data." + "fileUploader": { + "chooseFiles": "Choose files to upload", + "dragFiles": "Drag files here \n or", + "release": "Release to upload" + }, + "label": { + "dateNotProvided": "Date not provided", + "description": "Description", + "either": "Either", + "itemEditorWarn": "Don't use the ItemsEditor for more than 100 items!", + "lastUpdated": "Last updated", + "no": "No", + "prettyNumber": "{{value, number}}", + "sortBy": "Sort By", + "stepsForDataPublication": "Steps for data publication completion", + "title": "Title", + "yes": "Yes" }, "paginate": { "numberOfItems": "{{count, number}} {{what, lowercase}}", diff --git a/locales/en/translations.json b/locales/en/translations.json index a250c9bb..28a91dc8 100644 --- a/locales/en/translations.json +++ b/locales/en/translations.json @@ -1,260 +1,249 @@ { - "Genesys PGR": "Genesys PGR", - "Not found": "Not found", - "Nothing matches your request": "Nothing matches your request", - "footer": { - "About Genesys": "About Genesys", - "Contact Us": "Contact us", - "Copyright policy": "Copyright policy", - "Disclaimer": "Disclaimer", - "Privacy policy": "Privacy policy", - "Report an issue": "Report an issue", - "Source code": "Source code", - "Terms and Conditions of Use": "Terms and Conditions of Use", - "Translate Genesys": "Translate Genesys", - "copyright": "© {{from}} - {{to}} Data providers and the Crop Trust" - }, - "label": { - "crop": "Crop", - "crop_plural": "Crops", - "metadata": "Record metadata", - "subset": "Subset", - "subset_plural": "Subsets", - "accession": "Accession", - "accession_plural": "Accessions", - "institute": "Institute", - "institute_plural": "Institutes" - }, - "m": { - "crop": { - "helper": "Contact helpdesk@genesys-pgr.org to register additional crops." - } - }, - "menu": { - "Accessions": "Accessions", - "Controlled vocabularies": "Controlled vocabularies", - "Crops": "Crops", - "Datasets": "Datasets", - "Descriptor lists": "Crop descriptors", - "Descriptors": "Descriptors", - "Home": "Home", - "My Dashboard": "My dashboard", - "My profile": "My profile", - "My List": "My List", - "Partners": "Partners", - "Subsets": "Subsets", - "Institutes": "Institutes", - "Admin": "Administration", - "login": "Login", - "register": "Registration" - }, - "content": { - "menu": { - "about": "About Genesys", - "contact": "Contact us", - "what-is-genesys": "What is Genesys?", - "history-of-genesys": "History of Genesys", - "newsletter": "Genesys Newsletter", - "faq": "Frequently asked questions", - "how-to-use-genesys": "How to use Genesys?", - "disclaimer": "Disclaimer", - "terms": "Terms and Conditions of Use", - "copying": "Copyright policy", - "privacy": "Privacy policy" - } - }, - "p": { - "crop": { - "subtitle": "List of crops registered with Genesys", - "title": "Crops" - }, - "dashboard": { - "title": "My Dashboard", - "subtitle": "Manage data published on Genesys", - "profile": { - "title": "User profile", - "password": { - "disable to change pass": "You can't set your password if you use Google auth", - "title": "Password change", - "New password": "New password", - "Old password": "Old password", - "Confirm password": "Confirm password" + + "public": { + "p": { + "welcome": { + "About Genesys PGR": "About the Genesys PGR", + "Bookmark this page": "Bookmark this page", + "Contribute to Genesys": "Contribute to Genesys", + "Subscribe to Newsletter": "Subscribe to Newsletter", + "search": { + "placeholder": "Search Genesys...", + "suggestion0": "Try 'maize' or 'wild triticum'", + "suggestion1": "How about 'rice'", + "suggestion2": "What is 'MARDI' up to?", + "suggestion3": "'IRGC 1000' maybe", + "suggestion4": "Try 'leaf shape'", + "suggestion5": "Anything on 'cassava'?", + "suggestion6": "Maybe 'drought'" } } }, - "admin": { - "users": { - "list": "Registered user accounts", - "profile": { - "information": "User profile information", - "edit": { - "title": "Update user profile", - "fullName": "Full name", - "email": "E-mail address", - "roles": "User roles" - } - } - }, - "repository": { - "file": { - "formTitle": "Update file metadata", - "form": { - "title": "Title", - "description": "Description", - "subject": "Subject", - "rightsHolder": "Rights Holder", - "originalUrl": "Original URL", - "license": "License", - "extent": "Extent", - "creator": "Creator", - "contentType": "Content Type", - "bibliographicCitation": "Bibliographic Citation", - "accessRights": "Access Rights" - } + "search": { + "group": { + "descriptor": "Descriptors", + "accession": "Accessions", + "crop": "Crops", + "partner": "Data providers", + "dataset": "Datasets" + } + }, + "prettyF": { + "NOT": "Excluding {{what}}", + "accessions": { + "crop": "Crop", + "acceNumb": "Accession number", + "seqNo": "Sequential number", + "sampStat": "Biological status", + "storage": "Storage", + "geo": { + "latitude": "Latitude", + "longitude": "Longitude", + "elevation": "Elevation" }, - "folder": { - "createDialogTitle": "Create new folder", - "createBtn": "Create new folder", - "updateDialogTitle": "Update folder metadata", - "updateBtn": "Edit folder", - "form": { - "title": "Title", - "description": "Description", - "name": "Folder name" + "holder": { + "code": "Holder", + "country": { + "iso3": "Holder country", + "region": "Holder region" } + }, + "lastModifiedDate": { + "": "Last updated", + "ge": "Updated after", + "le": "Updated before" + }, + "taxa": { + "genus": "Genus", + "species": "Species", + "subtaxa": "Subtaxa" + }, + "origin": { + "iso3": "Origin" + }, + "taxonomy": { + "genus": "Genus", + "species": "Species", + "subtaxa": "Subtaxon" + }, + "sgsv": "Svalbard", + "mlsStatus": "MLS", + "available": "Available", + "historic": "Historic" + }, + "subsets": { + "title": "Title", + "crop": "Crop", + "institutes": "Institute code", + "description": "Description" + }, + "wiews": { + "code": "Institute code", + "accessions": "Accessions in Genesys", + "country": { + "iso3": "Country code" } + }, + "users": { + "role": "Role", + "enabled": "Active", + "expired": "Exptired", + "locked": "Locked", + "email": "E-mail address", + "uuid": "UUID" } } }, - "stats": { - "Accessions": "Accession record", - "Accessions_plural": "Accession records", - "Phenotypic datasets": "C&E Dataset", - "Phenotypic_plural datasets": "C&E Datasets", - "Subsets": "Subset", - "Subsets_plural": "Subsets", - "Institutes": "Institute", - "Institutes_plural": "Institutes" + "dashboard": { + "p": { + "dashboard": { + "title": "My Dashboard", + "subtitle": "Manage data published on Genesys" + } + } }, - "welcome": { - "About Genesys PGR": "About the Genesys PGR", - "Bookmark this page": "Bookmark this page", - "Contribute to Genesys": "Contribute to Genesys", - "Subscribe to Newsletter": "Subscribe to Newsletter", - "search": { - "placeholder": "Search Genesys...", - "suggestion0": "Try 'maize' or 'wild triticum'", - "suggestion1": "How about 'rice'", - "suggestion2": "What is 'MARDI' up to?", - "suggestion3": "'IRGC 1000' maybe", - "suggestion4": "Try 'leaf shape'", - "suggestion5": "Anything on 'cassava'?", - "suggestion6": "Maybe 'drought'" + "common": { + "Genesys PGR": "Genesys PGR", + "Not found": "Not found", + "Nothing matches your request": "Nothing matches your request", + "label": { + "metadata": "Record metadata" + }, + "footer": { + "About Genesys": "About Genesys", + "Contact Us": "Contact us", + "Copyright policy": "Copyright policy", + "Disclaimer": "Disclaimer", + "Privacy policy": "Privacy policy", + "Report an issue": "Report an issue", + "Source code": "Source code", + "Terms and Conditions of Use": "Terms and Conditions of Use", + "Translate Genesys": "Translate Genesys", + "copyright": "© {{from}} - {{to}} Data providers and the Crop Trust" + }, + "menu": { + "Controlled vocabularies": "Controlled vocabularies", + "Datasets": "Datasets", + "Descriptor lists": "Crop descriptors", + "Descriptors": "Descriptors", + "Home": "Home", + "My Dashboard": "My dashboard", + "My profile": "My profile", + "Partners": "Partners", + "Admin": "Administration", + "login": "Login", + "register": "Registration" } }, - "dataset": { - "creator": { - "role": { - "MANAGER": "Data manager", - "COLLECTOR": "Data collector", - "DIGITIZER": "Data digitizer", - "CURATOR": "Data curator" - }, - "roledesc": { - "MANAGER": "Responsible of the planning and execution of the germplasm characterization and evaluation activity which resulted in the dataset. Oversees the collection and management of characterization and evaluation data, and has final sign-off on publication.", - "COLLECTOR": "Records germplasm characterization or evaluation data in the field.", - "DIGITIZER": "Digitizes data.", - "CURATOR": "Organizes and validates data and metadata in correct format, ensures quality of both." + "datasets": { + "common": { + "modelName": "Dataset", + "modelName_plural": "Datasets", + "stats": "C&E Dataset", + "stats_plural": "C&E Datasets", + "creator": { + "role": { + "MANAGER": "Data manager", + "COLLECTOR": "Data collector", + "DIGITIZER": "Data digitizer", + "CURATOR": "Data curator" + }, + "roledesc": { + "MANAGER": "Responsible of the planning and execution of the germplasm characterization and evaluation activity which resulted in the dataset. Oversees the collection and management of characterization and evaluation data, and has final sign-off on publication.", + "COLLECTOR": "Records germplasm characterization or evaluation data in the field.", + "DIGITIZER": "Digitizes data.", + "CURATOR": "Organizes and validates data and metadata in correct format, ensures quality of both." + } } } }, - "search": { - "group": { - "descriptor": "Descriptors", - "accession": "Accessions", - "crop": "Crops", - "partner": "Data providers", - "dataset": "Datasets" + "geo": { + "common": { + "location": "Location", + "latitude": "Latitude", + "longitude": "Longitude", + "address": "Address", + "country": "Country" } - }, - "f": { - "NOT": "Excluding {{what}}", - "accessions": { - "crop": "Crop", - "acceNumb": "Accession number", - "seqNo": "Sequential number", - "sampStat": "Biological status", - "storage": "Storage", - "geo": { - "latitude": "Latitude", - "longitude": "Longitude", - "elevation": "Elevation" - }, - "holder": { - "code" : "Holder", - "country": { - "iso3": "Holder country", - "region": "Holder region" - } - }, - "lastModifiedDate": { - "": "Last updated", - "ge": "Updated after", - "le": "Updated before" - }, - "taxa": { - "genus": "Genus", - "species": "Species", - "subtaxa": "Subtaxa" - }, - "origin": { - "iso3": "Origin" - }, - "taxonomy": { - "genus": "Genus", - "species": "Species", - "subtaxa": "Subtaxon" + } +,"accessions": { + "public": { + "c": { + "accessionCard": { + "addToMyList": "Add to my list" }, - "sgsv": "Svalbard", - "mlsStatus": "MLS", - "available": "Available", - "historic": "Historic" + "pdciTable": { + "pdciScore": "PDCI score of this accession is {{score, number}} of 10.0.", + "readPDCI": "Read about Passport Data Completeness Index", + "pdciInstitute": "Average PDCI score for this institute is {{score, number}}." + } }, - "subsets": { - "title": "Title", - "crop": "Crop", - "institutes": "Institute code", - "description": "Description" + "f": { + "filtersTitle": "Filter accessions", + "seqNumber": "Sequential number", + "subtaxon": "Subtaxon", + "originOfMaterial": "Origin of material", + "elevation": "Elevation", + "status": "Status", + "historic": "Historic records", + "available": "Available for distribution", + "mlsStatus": "Included in MLS", + "sgsv": "Backed up in SGSV" }, - "wiews": { - "code": "Institute code", - "accessions": "Accessions in Genesys", - "country": { - "iso3": "Country code" + "p": { + "display": { + "title": "Accession details", + "subTitle": "Passport data and everything else", + "removeFromMyList": "Remove {{accessionNumber}} from my list", + "addToMyList": "Add {{accessionNumber}} to my list", + "holdingInstitute": "Holding institute", + "DOI": "DOI", + "acquisitionDate": "Acquisition Date", + "availability": "Availability for distribution", + "ITPGRFAMLS": "ITPGRFA MLS", + "donorInstitute": "Donor institute", + "donorAccessionNumber": "Donor accession number", + "safetyDuplicationInstitute": "Safety duplication institute", + "accessionURL": "Accession URL", + "scientificName": "Scientific name", + "cropName": "Crop name", + "providedCropName": "Provided crop name", + "accessionNames": "Accession names", + "collectingInformation": "Collecting information", + "remarks": "Remarks", + "pdci": "Passport Data Completeness Index", + "metadata": "Metadata", + "permanentURL": "Permanent URL", + "associatedDatasets": "Associated Datasets", + "associatedSubsets": "Associated Subsets" + }, + "browse": { + "title": "Accession browser", + "subTitle": "Explore curated sets of accessions" } - }, - "users": { - "role": "Role", - "enabled": "Active", - "expired": "Exptired", - "locked": "Locked", - "email": "E-mail address", - "uuid": "UUID" } }, - "subset": { - "creator": { - "role": { - "MANAGER": "Data manager", - "DIGITIZER": "Data digitizer", - "COLLECTOR": "Data collector", - "CURATOR": "Data curator" - } - } + "tab": { + "data": "Accessions", + "overview": "Overview", + "map": "Map" }, - "accession": { - "pdciScore": "PDCI score of this accession is {{score, number}} of 10.0.", - "pdciInstitute": "Average PDCI score for this institute is {{score, number}}.", + "common": { + "modelName": "Accession", + "modelName_plural": "Accessions", + "menu": "Accessions", + "stats": "Accession record", + "stats_plural": "Accession records", + "acceNumb": "Accession number", + "countryOfOrigin": "Country of origin", + "instituteCode": "Institute code", + "taxonomy": "Taxonomy", + "genus": "Genus", + "species": "Species", + "doi": "DOI", + "sampStat": "Biological status of accession", + "storageType": "Type of germplasm storage", + "alias": { "OTHERNUMB": "Other identifier", "ACCENAME": "Accession name", @@ -339,27 +328,485 @@ "sgsv": "Safety duplicated in Svalbard", "storage": "Type of Germplasm storage" } + } +} +,"cms": { + "menu": { + "about": "About Genesys", + "contact": "Contact us", + "what-is-genesys": "What is Genesys?", + "history-of-genesys": "History of Genesys", + "newsletter": "Genesys Newsletter", + "faq": "Frequently asked questions", + "how-to-use-genesys": "How to use Genesys?", + "disclaimer": "Disclaimer", + "terms": "Terms and Conditions of Use", + "copying": "Copyright policy", + "privacy": "Privacy policy" + } +} + +,"crop": { + "public": { + "c": { + "cropCard": { + "originalName": "Original name", + "registered": "Registered" + }, + "cropSelector": { + "helper": "Contact helpdesk@genesys-pgr.org to register additional crops." + } + }, + "p": { + "display": { + "title": "Crop details", + "generalInformation": "General information", + "otherNames": "Other names" + }, + "browse": { + "title": "Crop list", + "subTitle": "Genesys crops directory", + "createCrop": "Create crop" + } + } + }, + "admin": { + "c": { + "cropForm": { + "cropCode": "Crop code", + "cropTitle": "Crop title", + "otherNames": "Other names", + "version": "Version: {{version: numeric}}", + "alreadyInUse": "Already in use" + } + }, + "p": { + "edit": { + "onDelete": { + "message": "Delete crop '{{cropName, lowercase}}'?", + "description": "Note, deleting any crop causes mayhem." + } + } + } + }, + "common": { + "modelName": "Crop", + "modelName_plural": "Crops", + "menu": "Crops", + "accessionsInGenesys": "Accessions in genesys" + } +} +,"institutes": { + "public": { + "c": { + "instituteCard": { + "accessionsInGenesys": "Accessions in Genesys: {{count, numeric}}" + } + }, + "f": { + "title": "Filter institutes", + "instituteName": "Institute name" + }, + "p": { + "browse": { + "title": "WIEWS Institutes", + "subTitle": "Explore wiews institutes" + }, + "display": { + "title": "Institute details", + "type": "Type", + "webLink": "Web link", + "about": "About", + "representedCrops": "Most represented Crops", + "representedCropNames": "Most represented Crop names", + "representedGenera": "Most represented Genera", + "representedSpecies": "Most represented Species", + "lastUpdates": "Last updates of passport data", + "PDCI": "PDCI: Passport data complex index", + "readPDCI": "Read about Passport Data Completeness Index", + "pdciScore": "Average PDCI score for {{count, number}} accessions is {{avg, number}}, with minimum score of {{min, number}} and maximum score of {{max, number}}." + } + } }, - "request": { + "sort": { + "instituteCode": "Institute code" + }, + "common": { + "modelName": "Institute", + "modelName_plural": "Institutes", + "menu": "Institutes", + "stats": "Institute", + "stats_plural": "Institutes", + "instCode": "INSTCODE", + "instituteCode": "Institute code", + "accessionsInGenesys": "Accessions in Genesys" + } +} +,"list": { + "public": { + "p": { + "browse": { + "title": "Selected accessions", + "subTitle": "As you explore the millions of accessions held in Genesys, you can create your own list to keep track of the results of your search. Your selections are stored here so you can return to them at any time.", + "sendRequest": "Send request", + "noAccessions": "You have not added any accessions to the list." + } + } + }, + "common": { + "menu": "My List" + } +} +,"repository": { + "admin": { + "p": { + "editFile": { + "formTitle": "Update file metadata" + }, + "imageGallery": { + "toFolder": "To folder", + "deleteGallery": "Delete gallery", + "deleteGalleryAlert": "Gallery at {{folderPath, string}} could not be deleted." + }, + "repositoryBrowser": { + "viewGallery": "View gallery", + "createGallery": "Create gallery", + "createGalleryAlert": "Image gallery at {{folderPath, string}} could not be created.", + "deleteFolder": "Delete folder", + "deleteFolderAlert": "Folder {{folderPath, string}} could not be deleted." + } + }, + "dialog": { + "updateFolder": { + "updateDialogTitle": "Update folder metadata", + "updateBtn": "Edit folder" + }, + "createFolder": { + "createDialogTitle": "Create new folder", + "createBtn": "Create new folder" + } + }, + "c": { + "common": { + "path": "Path", + "registered": "Registered" + }, + "fileCard": { + "originalName": "Original name" + }, + "fileForm": { + "subject": "Subject", + "rightsHolder": "Rights Holder", + "originalUrl": "Original URL", + "license": "License", + "extent": "Extent", + "creator": "Creator", + "contentType": "Content Type", + "bibliographicCitation": "Bibliographic Citation", + "accessRights": "Access Rights" + }, + "folderCrumbs": { + "root": "ROOT" + }, + "folderForm": { + "form": { + "name": "Folder name" + } + } + } + } +} +,"requests": { + "public": { + "p": { + "stepper": { + "accessionsList": { + "title": "Out of {{count, number}} accessions listed, {{available, number}} are known to be available for distribution.", + "stepName": "Review list of material" + }, + "confirm": { + "instructions": "Once you push **submit request** button your request will be validated.\n\nCheck your email and also check your SPAM folder for a validation message from Genesys.\n\nThe email address provided will be checked against ITPGRFA's Easy-SMTA database.", + "stepName": "Finalize and submit" + }, + "requestInfo": { + "stepName": "Personal information", + "email": "Your e-mail address as registered in Easy-SMTA", + "preacceptSMTA": "SMTA/MTA acceptance:", + "preacceptSMTATrue": "I will accept the terms and conditions of SMTA/MTA", + "preacceptSMTAFalse": "I will NOT accept the terms and conditions of SMTA/MTA", + "purposeType": "Specify use of material:", + "notes": "Additional notes to submit with your request" + } + } + } + }, + "admin": { + "p": { + "browse": { + "title": "{{totalElements, number}} requests for PGR material" + }, + "display": { + "title": "Request from {{email, string}}", + "sendValidationEmail": "Send validation email", + "validateRequest": "Validate Request", + "recheckPID": "Recheck PID", + "requestInformation": "Request information", + "recipientPIDInformation": "Recipient PID information", + "shippingAddress": "Shipping address", + "notes": "Notes", + "dispatchedTo": "Dispatched to", + "requestedAccessionIds": "Requested accession ids" + } + } + }, + "common": { + "modelMame": "Request", + "modelMame_plural": "Requests", "preacceptSMTA": "Preaccept SMTA", + "stateLabel": "State", "state": { - "0": "Not validated" , + "0": "Not validated", "1": "Validated", "2": "Dispatched" }, + "typeLabel": "Type", "type": { "in": "Individual", "or": "Organizational" }, + "purposeTypeLabel": "Purpose type", "purposeType": { "0": "Other (please elaborate in Notes field)", "1": "Research for food and agriculture" + } + } +} +,"subsets": { + "public": { + "c": { + "subsetCard": { + "crops": "Crops", + "numberOfAccessions": "Number of accessions", + "institute": "Institute", + "license": "License", + "creationDate": "Creation date", + "source": "Source" + }, + "subsetDisplay": { + "subsetCreators": "Subset creators" + } + }, + "f": { + "filterTitle": "Filter subsets", + "textSearch": "Text search", + "title": "Title", + "titlePlaceholder": "International", + "description": "Description", + "descriptionPlaceholder": "Subset description", + "institute": "Institute", + "institutePlaceholder": "MEX002", + "crop": "Crop" + }, + "p": { + "browse": { + "title": "Subset browser", + "subTitle": "Explore curated sets of subsets" + }, + "display": { + "title": "Subset {{subsetTitle: string}}" + } + } + }, + "dashboard": { + "c": { + "dashboard": { + "no": "No.", + "publisher": "Publisher", + "status": "Status" + } + }, + "menu": { + "subsets": "Subsets", + "listSubsets": "List subsets", + "createSubsets": "Create subset" + }, + "p": { + "stepper": { + "accessionList": { + "stepName": "List of accessions", + "instructions": "INSTRUCTIONS FOR USE", + "Subset template": "Subset template", + "detailedInstructions1": "Use \"Acccessions\" sheet from template: ", + "detailedInstructions2": "Do not change header name in the template:", + "detailedInstructions3": "Fill the template with the information of the accessions, save it.", + "detailedInstructions4": "Copy and paste the table from Excel into the text field below.", + "listOfAccessions": "List of accessions described in the dataset", + "pasteData": "Paste accessions data here (comma separated)", + "accessionListCount": "Accession list: {{count, numeric}} rows" + }, + "basicInfo": { + "stepName": "Basic information", + "subsetTitle": "Subset title", + "instituteCode": "Institute code", + "subsetDescription": "Subset description", + "subsetDescriptionPlaceholder": "An abstract, short or long description of the resource. Descriptive details improves discoverability of the resource.", + "crops": "Crops", + "rights": "Rights", + "creationDate": "Creation date", + "source": "Source" + }, + "creators": { + "stepName": "Subset creators", + "Role": "Role: ", + "fullName": "Full name", + "fullNamePlaceholder": "Jane A. Doe", + "institutionalAffiliation": "Institutional affiliation", + "institutionalAffiliationPlaceholder": "Institutional affiliation", + "email": "Email address", + "emailPlaceholder": "name@domain.com", + "phone": "Phone number", + "phonePlaceholder": "+1 555 1231 Ext. 13", + "fax": "Fax", + "faxPlaceholder": "+1 555 1231 Ext. 42", + "address": "Address", + "addressPlaceholder": "Address", + "addSubsetCreator": "Add subset creator" + }, + "review": { + "stepName": "Review and publish" + } + } + } + }, + "common": { + "modelName": "Subset", + "modelName_plural": "Subsets", + "menu": "Subsets", + "stats": "Subset", + "stats_plural": "Subsets", + "creators": { + "role": { + "MANAGER": "Data manager", + "DIGITIZER": "Data digitizer", + "COLLECTOR": "Data collector", + "CURATOR": "Data curator" + } + } + } +} +,"user": { + "public": { + "c": { + "loginForm": { + "userName": "Username", + "password": "Password", + "googleLogin": "Login with Google", + "login": "Login" + }, + "registrationForm": { + "password": "Password", + "passwordConfirm": "Repeat password", + "fullName": "Your full name", + "register": "Register" + }, + "userProfileCard": { + "accountExpires": "Account expires", + "lastLogin": "Last login", + "accountLocked": "Account locked:", + "lockedUntil": "Locked until:", + "accountActive": "Account active:" + } }, - "submit": { - "instructions": "Once you push **submit request** button your request will be validated.\n\nCheck your email and also check your SPAM folder for a validation message from Genesys.\n\nThe email address provided will be checked against ITPGRFA's Easy-SMTA database." + "p": { + "login": { + "title": "Welcome to Genesys", + "subTitle": "Log in to manage datasets" + }, + "registration": { + "title": "Create your account", + "register": "Register a new account" + } + } + }, + "admin": { + "f": { + "title": "Filter users", + "locked": "Account locked", + "enabled": "Account active", + "expired": "Account expired" + }, + "p": { + "browse": { + "title": "Registered user accounts" + }, + "display": { + "title": "User profile information", + "unlock": "Unlock", + "lock": "Lock", + "disable": "Disable", + "enable": "Enable", + "sendEmail": "Send validation E-mail" + }, + "edit": { + "title": "Update user profile" + } } }, - "institute": { - "Institute PDCI score": "Average PDCI score for {{count, number}} accessions is {{avg, number}}, with minimum score of {{min, number}} and maximum score of {{max, number}}." + "dashboard": { + "c": { + "passwordForm": { + "newPassword": "New password", + "oldPassword": "Old password", + "confirmPassword": "Confirm password", + "changePassword": "Change password" + } + }, + "menu": { + "profile": "Profile", + "userProfile": "User profile", + "changePassword": "Change password" + }, + "p": { + "changePassword": { + "unableChange": "You can't set your password if you use Google auth", + "title": "Password change" + }, + "profile": { + "title": "User profile" + } + } + }, + "common": { + "email": "Email", + "emailAddress": "E-mail address", + "name": "Name", + "fullName": "Full name", + "surname": "Surname", + "country": "Country", + "phone": "Phone", + "statusLabel": "Status", + "status": { + "locked": "Locked", + "enabled": "Active", + "expired": "Expired" + }, + "roleLabel": "User roles", + "role": { + "USER": "User", + "ADMINISTRATOR": "Administrator", + "EVERYONE": "Everyone", + "VALIDATEDUSER": "Validated user", + "VETTEDUSER": "Vetted user", + "CONTENTMANAGER": "Content manager" + }, + "typeLabel": "Account type", + "type": { + "local": "LOCAL", + "google": "GOOGLE", + "system": "SYSTEM", + "deleted": "DELETED", + "ldap": "LDAP" + } } } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index af034146..883964f0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -357,17 +357,15 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", "integrity": "sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==", - "dev": true, "requires": { "call-me-maybe": "^1.0.1", "glob-to-regexp": "^0.3.0" } }, "@nodelib/fs.stat": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.1.tgz", - "integrity": "sha512-KU/VDjC5RwtDUZiz3d+DHXJF2lp5hB9dn552TXIyptj8SH1vXmR40mG0JgGq03IlYsOgGfcv8xrLpSQ0YUMQdA==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-1.1.2.tgz", + "integrity": "sha512-yprFYuno9FtNsSHVlSWd+nRlmGoAbqbeCwOryP6sC/zoCjhpArcRMYp19EvpSUSizJAlsXEwJv+wcWS9XaXdMw==" }, "@types/jss": { "version": "9.5.3", @@ -384,11 +382,17 @@ "integrity": "sha512-m9zXmifkZsMHZBOyxZWilMwmTlpC8x5Ty360JKTiXvlXZfBWYpsg9ZZvP/Ye+iZUh+Q+MxDLjItVTWIsfwz+8Q==", "dev": true }, + "@types/prop-types": { + "version": "15.5.6", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.5.6.tgz", + "integrity": "sha512-ZBFR7TROLVzCkswA3Fmqq+IIJt62/T7aY/Dmz+QkU7CaW2QFqAitCE8Ups7IzmGhcN1YWMBT4Qcoc07jU9hOJQ==" + }, "@types/react": { - "version": "16.4.6", - "resolved": "https://registry.npmjs.org/@types/react/-/react-16.4.6.tgz", - "integrity": "sha512-9LDZdhsuKSc+DjY65SjBkA958oBWcTWSVWAd2cD9XqKBjhGw1KzAkRhWRw2eIsXvaIE/TOTjjKMFVC+JA1iU4g==", + "version": "16.4.18", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.4.18.tgz", + "integrity": "sha512-eFzJKEg6pdeaukVLVZ8Xb79CTl/ysX+ExmOfAAqcFlCCK5TgFDD9kWR0S18sglQ3EmM8U+80enjUqbfnUyqpdA==", "requires": { + "@types/prop-types": "*", "csstype": "^2.2.0" } }, @@ -853,20 +857,17 @@ "arr-diff": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=" }, "arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" }, "arr-union": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=" }, "array-find-index": { "version": "1.0.2", @@ -907,8 +908,7 @@ "array-unique": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=" }, "arrify": { "version": "1.0.1", @@ -969,8 +969,7 @@ "assign-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=" }, "async": { "version": "2.6.0", @@ -1001,8 +1000,7 @@ "atob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.1.tgz", - "integrity": "sha1-ri1acpR38onWDdf5amMUoi3Wwio=", - "dev": true + "integrity": "sha1-ri1acpR38onWDdf5amMUoi3Wwio=" }, "autobind-decorator": { "version": "2.1.0", @@ -2012,7 +2010,6 @@ "version": "0.11.2", "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, "requires": { "cache-base": "^1.0.1", "class-utils": "^0.3.5", @@ -2027,7 +2024,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, "requires": { "is-descriptor": "^1.0.0" } @@ -2036,7 +2032,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -2045,7 +2040,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -2054,7 +2048,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", @@ -2085,6 +2078,11 @@ "tweetnacl": "^0.14.3" } }, + "before-build-webpack": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/before-build-webpack/-/before-build-webpack-0.2.5.tgz", + "integrity": "sha512-C0JfCFlKIRchTJ6LX0/bYyCvwjMUm8s3Hf/FZXluZmzx6Ho/GjqBSMyGtzMT+n20rWx4on4GB7eb87eRaJEuow==" + }, "big.js": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", @@ -2186,7 +2184,6 @@ "version": "2.3.2", "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, "requires": { "arr-flatten": "^1.1.0", "array-unique": "^0.3.2", @@ -2204,7 +2201,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, "requires": { "is-extendable": "^0.1.0" } @@ -2388,7 +2384,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, "requires": { "collection-visit": "^1.0.0", "component-emitter": "^1.2.1", @@ -2458,8 +2453,7 @@ "call-me-maybe": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", - "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=", - "dev": true + "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=" }, "camel-case": { "version": "3.0.0", @@ -2640,7 +2634,6 @@ "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, "requires": { "arr-union": "^3.1.0", "define-property": "^0.2.5", @@ -2652,7 +2645,6 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, "requires": { "is-descriptor": "^0.1.0" } @@ -2806,7 +2798,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, "requires": { "map-visit": "^1.0.0", "object-visit": "^1.0.0" @@ -2876,8 +2867,7 @@ "component-emitter": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", - "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", - "dev": true + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=" }, "compressible": { "version": "2.0.14", @@ -3034,8 +3024,7 @@ "copy-descriptor": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=" }, "copy-webpack-plugin": { "version": "4.5.2", @@ -4189,7 +4178,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, "requires": { "is-descriptor": "^1.0.2", "isobject": "^3.0.1" @@ -4199,7 +4187,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -4208,7 +4195,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -4217,7 +4203,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", @@ -4801,7 +4786,6 @@ "version": "2.1.4", "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, "requires": { "debug": "^2.3.3", "define-property": "^0.2.5", @@ -4816,7 +4800,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "requires": { "ms": "2.0.0" } @@ -4825,7 +4808,6 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, "requires": { "is-descriptor": "^0.1.0" } @@ -4834,7 +4816,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, "requires": { "is-extendable": "^0.1.0" } @@ -4958,7 +4939,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, "requires": { "assign-symbols": "^1.0.0", "is-extendable": "^1.0.1" @@ -4968,7 +4948,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, "requires": { "is-plain-object": "^2.0.4" } @@ -5001,7 +4980,6 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, "requires": { "array-unique": "^0.3.2", "define-property": "^1.0.0", @@ -5017,7 +4995,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, "requires": { "is-descriptor": "^1.0.0" } @@ -5026,7 +5003,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, "requires": { "is-extendable": "^0.1.0" } @@ -5035,7 +5011,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -5044,7 +5019,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -5053,7 +5027,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", @@ -5129,10 +5102,9 @@ "dev": true }, "fast-glob": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.2.tgz", - "integrity": "sha512-TR6zxCKftDQnUAPvkrCWdBgDq/gbqx8A3ApnBrR5rMvpp6+KMJI0Igw7fkWPgeVK0uhRXTXdvO3O+YP0CaUX2g==", - "dev": true, + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.3.tgz", + "integrity": "sha512-NiX+JXjnx43RzvVFwRWfPKo4U+1BrK5pJPsHQdKMlLoFHrrGktXglQhHliSihWAq+m1z6fHk3uwGHrtRbS9vLA==", "requires": { "@mrmlnc/readdir-enhanced": "^2.2.1", "@nodelib/fs.stat": "^1.0.1", @@ -5229,7 +5201,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, "requires": { "extend-shallow": "^2.0.1", "is-number": "^3.0.0", @@ -5241,7 +5212,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, "requires": { "is-extendable": "^0.1.0" } @@ -5376,8 +5346,7 @@ "for-in": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" }, "for-own": { "version": "1.0.0", @@ -5419,7 +5388,6 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, "requires": { "map-cache": "^0.2.2" } @@ -6060,8 +6028,7 @@ "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=" }, "getpass": { "version": "0.1.7", @@ -6087,9 +6054,9 @@ "dev": true }, "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", "dev": true, "requires": { "fs.realpath": "^1.0.0", @@ -6140,7 +6107,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, "requires": { "is-glob": "^3.1.0", "path-dirname": "^1.0.0" @@ -6150,7 +6116,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, "requires": { "is-extglob": "^2.1.0" } @@ -6199,8 +6164,7 @@ "glob-to-regexp": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz", - "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=", - "dev": true + "integrity": "sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=" }, "global": { "version": "4.3.2", @@ -6337,7 +6301,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, "requires": { "get-value": "^2.0.6", "has-values": "^1.0.0", @@ -6348,7 +6311,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, "requires": { "is-number": "^3.0.0", "kind-of": "^4.0.0" @@ -6358,7 +6320,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, "requires": { "is-buffer": "^1.1.5" } @@ -7071,7 +7032,6 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, "requires": { "kind-of": "^3.0.2" }, @@ -7080,7 +7040,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, "requires": { "is-buffer": "^1.1.5" } @@ -7160,7 +7119,6 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, "requires": { "kind-of": "^3.0.2" }, @@ -7169,7 +7127,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, "requires": { "is-buffer": "^1.1.5" } @@ -7191,7 +7148,6 @@ "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, "requires": { "is-accessor-descriptor": "^0.1.6", "is-data-descriptor": "^0.1.4", @@ -7201,8 +7157,7 @@ "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==" } } }, @@ -7230,14 +7185,12 @@ "is-extendable": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" }, "is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" }, "is-finite": { "version": "1.0.2", @@ -7266,7 +7219,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", - "dev": true, "requires": { "is-extglob": "^2.1.1" } @@ -7291,7 +7243,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, "requires": { "kind-of": "^3.0.2" }, @@ -7300,7 +7251,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, "requires": { "is-buffer": "^1.1.5" } @@ -7448,8 +7398,7 @@ "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==" }, "is-word-character": { "version": "1.0.1", @@ -7465,8 +7414,7 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" }, "isexe": { "version": "2.0.0", @@ -7740,8 +7688,7 @@ "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==" }, "klaw": { "version": "1.3.1", @@ -8137,8 +8084,7 @@ "map-cache": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=" }, "map-obj": { "version": "1.0.1", @@ -8150,7 +8096,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, "requires": { "object-visit": "^1.0.0" } @@ -8257,10 +8202,9 @@ "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" }, "merge2": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.2.tgz", - "integrity": "sha512-bgM8twH86rWni21thii6WCMQMRMmwqqdW3sGWi9IipnVAszdLXRjwDwAnyrVXo6DuP3AjRMMttZKUB48QWIFGg==", - "dev": true + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.2.3.tgz", + "integrity": "sha512-gdUU1Fwj5ep4kplwcmftruWofEFt6lfpkkr3h860CXbAB9c3hGb55EOL2ali0Td5oebvW0E1+3Sr+Ur7XfKpRA==" }, "methods": { "version": "1.1.2", @@ -8271,7 +8215,6 @@ "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, "requires": { "arr-diff": "^4.0.0", "array-unique": "^0.3.2", @@ -8388,7 +8331,6 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", - "dev": true, "requires": { "for-in": "^1.0.2", "is-extendable": "^1.0.1" @@ -8398,7 +8340,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, "requires": { "is-plain-object": "^2.0.4" } @@ -8496,7 +8437,6 @@ "version": "1.2.13", "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, "requires": { "arr-diff": "^4.0.0", "array-unique": "^0.3.2", @@ -8797,7 +8737,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, "requires": { "copy-descriptor": "^0.1.0", "define-property": "^0.2.5", @@ -8808,7 +8747,6 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, "requires": { "is-descriptor": "^0.1.0" } @@ -8817,7 +8755,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, "requires": { "is-buffer": "^1.1.5" } @@ -8840,7 +8777,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, "requires": { "isobject": "^3.0.0" } @@ -8892,7 +8828,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, "requires": { "isobject": "^3.0.1" } @@ -9269,8 +9204,7 @@ "pascalcase": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=" }, "path-browserify": { "version": "0.0.0", @@ -9281,8 +9215,7 @@ "path-dirname": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=" }, "path-exists": { "version": "3.0.0", @@ -9558,8 +9491,7 @@ "posix-character-classes": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=" }, "postcss": { "version": "6.0.23", @@ -14349,7 +14281,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, "requires": { "extend-shallow": "^3.0.2", "safe-regex": "^1.1.0" @@ -14508,8 +14439,7 @@ "repeat-element": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", - "dev": true + "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=" }, "repeat-string": { "version": "1.6.1", @@ -14678,8 +14608,7 @@ "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=" }, "resolve-url-loader": { "version": "2.3.0", @@ -14719,8 +14648,7 @@ "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==" }, "rework": { "version": "1.0.1", @@ -14830,7 +14758,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, "requires": { "ret": "~0.1.10" } @@ -15095,7 +15022,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", - "dev": true, "requires": { "extend-shallow": "^2.0.1", "is-extendable": "^0.1.1", @@ -15107,7 +15033,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, "requires": { "is-extendable": "^0.1.0" } @@ -15218,7 +15143,6 @@ "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, "requires": { "base": "^0.11.1", "debug": "^2.2.0", @@ -15234,7 +15158,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "requires": { "ms": "2.0.0" } @@ -15243,7 +15166,6 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, "requires": { "is-descriptor": "^0.1.0" } @@ -15252,7 +15174,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, "requires": { "is-extendable": "^0.1.0" } @@ -15263,7 +15184,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, "requires": { "define-property": "^1.0.0", "isobject": "^3.0.0", @@ -15274,7 +15194,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, "requires": { "is-descriptor": "^1.0.0" } @@ -15283,7 +15202,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -15292,7 +15210,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, "requires": { "kind-of": "^6.0.0" } @@ -15301,7 +15218,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", "is-data-descriptor": "^1.0.0", @@ -15314,7 +15230,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, "requires": { "kind-of": "^3.2.0" }, @@ -15323,7 +15238,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, "requires": { "is-buffer": "^1.1.5" } @@ -15392,8 +15306,7 @@ "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" }, "source-map-loader": { "version": "0.2.3", @@ -15430,7 +15343,6 @@ "version": "0.5.2", "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", - "dev": true, "requires": { "atob": "^2.1.1", "decode-uri-component": "^0.2.0", @@ -15451,8 +15363,7 @@ "source-map-url": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", - "dev": true + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=" }, "spdx-correct": { "version": "1.0.2", @@ -15536,7 +15447,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, "requires": { "extend-shallow": "^3.0.0" } @@ -15595,7 +15505,6 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, "requires": { "define-property": "^0.2.5", "object-copy": "^0.1.0" @@ -15605,7 +15514,6 @@ "version": "0.2.5", "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, "requires": { "is-descriptor": "^0.1.0" } @@ -16684,7 +16592,6 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, "requires": { "kind-of": "^3.0.2" }, @@ -16693,7 +16600,6 @@ "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, "requires": { "is-buffer": "^1.1.5" } @@ -16704,7 +16610,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, "requires": { "define-property": "^2.0.2", "extend-shallow": "^3.0.2", @@ -16716,7 +16621,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, "requires": { "is-number": "^3.0.0", "repeat-string": "^1.6.1" @@ -17084,7 +16988,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", - "dev": true, "requires": { "arr-union": "^3.1.0", "get-value": "^2.0.6", @@ -17096,7 +16999,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, "requires": { "is-extendable": "^0.1.0" } @@ -17105,7 +17007,6 @@ "version": "0.4.3", "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", - "dev": true, "requires": { "extend-shallow": "^2.0.1", "is-extendable": "^0.1.1", @@ -17215,7 +17116,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, "requires": { "has-value": "^0.3.1", "isobject": "^3.0.0" @@ -17225,7 +17125,6 @@ "version": "0.3.1", "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, "requires": { "get-value": "^2.0.3", "has-values": "^0.1.4", @@ -17236,7 +17135,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, "requires": { "isarray": "1.0.0" } @@ -17246,8 +17144,7 @@ "has-values": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=" } } }, @@ -17275,8 +17172,7 @@ "urix": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=" }, "url": { "version": "0.11.0", @@ -17339,8 +17235,7 @@ "use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" }, "util": { "version": "0.10.3", diff --git a/package.json b/package.json index e3465453..f0c0d465 100644 --- a/package.json +++ b/package.json @@ -19,16 +19,17 @@ "main": "index.js", "scripts": { "clean": "rimraf target", - "build": "webpack --config config/webpack-development.config.js", + "build": "npm run generateI18n && webpack --config config/webpack-development.config.js", "build:production": "cross-env NODE_ENV=production SSR=true webpack --config config/webpack-production.config.js", "build:server": "cross-env NODE_ENV=production SSR=true webpack --config config/server.config.js", - "serve": "webpack-dev-server --config config/webpack-development.config.js", + "serve": "npm run generateI18n && webpack-dev-server --config config/webpack-development.config.js", "serve:production": "cross-env NODE_ENV=production webpack-dev-server --config config/webpack-production.config.js", - "build:ssr": "rimraf target && npm run build:production && npm run build:server", + "build:ssr": "npm run generateI18n && rimraf target && npm run build:production && npm run build:server", "serve:ssr": "npm run build:ssr && cd target/app/server && cross-env SSR=true node server.js", "debug:ssr": "rimraf target && npm run build && cross-env SSR=true webpack --config config/server.config.js && cd target/app/server && cross-env SSR=true node server.js", "debug:ssr2": "cross-env SSR=true webpack --config config/server.config.js && cd target/app/server && cross-env SSR=true node server.js", "run:ssr": "cd target/app/server && cross-env SSR=true node server.js", + "generateI18n": "node i18n/generateI18n.ts", "i18nscan": "i18next-scanner --config i18next-scanner.config.js 'src/**/*.tsx'" }, "dependencies": { @@ -45,6 +46,7 @@ "es-cookie": "^1.2.0", "express": "^4.16.3", "express-http-proxy": "^1.2.0", + "fast-glob": "^2.2.3", "flattenjs": "^1.0.4", "form-data": "^2.3.2", "history": "^4.7.2", diff --git a/src/accessions/translations.json b/src/accessions/translations.json new file mode 100644 index 00000000..b973910f --- /dev/null +++ b/src/accessions/translations.json @@ -0,0 +1,164 @@ +{ + "public": { + "c": { + "accessionCard": { + "addToMyList": "Add to my list" + }, + "pdciTable": { + "pdciScore": "PDCI score of this accession is {{score, number}} of 10.0.", + "readPDCI": "Read about Passport Data Completeness Index", + "pdciInstitute": "Average PDCI score for this institute is {{score, number}}." + } + }, + "f": { + "filtersTitle": "Filter accessions", + "seqNumber": "Sequential number", + "subtaxon": "Subtaxon", + "originOfMaterial": "Origin of material", + "elevation": "Elevation", + "status": "Status", + "historic": "Historic records", + "available": "Available for distribution", + "mlsStatus": "Included in MLS", + "sgsv": "Backed up in SGSV" + }, + "p": { + "display": { + "title": "Accession details", + "subTitle": "Passport data and everything else", + "removeFromMyList": "Remove {{accessionNumber}} from my list", + "addToMyList": "Add {{accessionNumber}} to my list", + "holdingInstitute": "Holding institute", + "DOI": "DOI", + "acquisitionDate": "Acquisition Date", + "availability": "Availability for distribution", + "ITPGRFAMLS": "ITPGRFA MLS", + "donorInstitute": "Donor institute", + "donorAccessionNumber": "Donor accession number", + "safetyDuplicationInstitute": "Safety duplication institute", + "accessionURL": "Accession URL", + "scientificName": "Scientific name", + "cropName": "Crop name", + "providedCropName": "Provided crop name", + "accessionNames": "Accession names", + "collectingInformation": "Collecting information", + "remarks": "Remarks", + "pdci": "Passport Data Completeness Index", + "metadata": "Metadata", + "permanentURL": "Permanent URL", + "associatedDatasets": "Associated Datasets", + "associatedSubsets": "Associated Subsets" + }, + "browse": { + "title": "Accession browser", + "subTitle": "Explore curated sets of accessions" + } + } + }, + "tab": { + "data": "Accessions", + "overview": "Overview", + "map": "Map" + }, + "common": { + "modelName": "Accession", + "modelName_plural": "Accessions", + "menu": "Accessions", + "stats": "Accession record", + "stats_plural": "Accession records", + "acceNumb": "Accession number", + "countryOfOrigin": "Country of origin", + "instituteCode": "Institute code", + "taxonomy": "Taxonomy", + "genus": "Genus", + "species": "Species", + "doi": "DOI", + "sampStat": "Biological status of accession", + "storageType": "Type of germplasm storage", + + "alias": { + "OTHERNUMB": "Other identifier", + "ACCENAME": "Accession name", + "DONORNUMB": "Donor accession number", + "COLLNUMB": "Collecting number" + }, + "available": { + "true": "Available for distribution", + "false": "Not available for distribution", + "null": "Availability not provided" + }, + "mlsStatus": { + "true": "Accession is part of the Multi-lateral system of ITPGRFA", + "false": "Not declared in the Multi-lateral system of ITPGRFA ", + "null": "Status not provided" + }, + "coll": { + "collCode": "Collecting institute code", + "collNumb": "Collecting number", + "collDate": "Collecting date of sample", + "collMissId": "Collecting mission identifier", + "collName": "Collecting institute name", + "collSite": "Location of collecting site", + "collSrc": "Collecting source" + }, + "geo": { + "latitude": "Latitude of collecting site", + "longitude": "Longitude of collecting site", + "uncertainty": "Coordinate uncertainty", + "datum": "Geodetic datum", + "method": "Georeferencing method", + "elevation": "Elevation of collecting site" + }, + "storage": { + "10": "Seed collection", + "11": "Short term seed collection", + "12": "Medium term seed collection", + "13": "Long term seed collection", + "20": "Field collection", + "30": "In vitro collection", + "40": "Cryopreserved collection", + "50": "DNA collection", + "99": "Other" + }, + "sampleStatus": { + "100": "Wild", + "110": "Natural", + "120": "Semi-natural/wild", + "130": "Semi-natural/sown", + "200": "Weedy", + "300": "Traditional cultivar/Landrace", + "400": "Breeding/Research Material", + "410": "Breeders Line", + "411": "Synthetic population", + "412": "Hybrid", + "413": "Founder stock/base population", + "414": "Inbred line", + "415": "Segregating population", + "416": "Clonal selection", + "420": "Genetic stock", + "421": "Mutant", + "422": "Cytogenetic stocks", + "423": "Other genetic stocks", + "500": "Advanced/improved cultivar", + "600": "GMO", + "999": "Other" + }, + "overview": { + "institute code": "Holding Institute", + "institute country code3": "Country of holding institute", + "crop shortName": "Crop name", + "cropName": "Crop", + "sampStat": "Biological status of accession", + "taxonomy genus": "Genus", + "taxonomy genusSpecies": "Species", + "countryOfOrigin code3": "Country of Origin", + "donorCode": "FAO WIEWS code of donor institute", + "mlsStatus": "ITGPRFA Multi-lateral system", + "available": "Available for distribution", + "duplSite": "Site of safety duplication", + "breederCode": "Breeder code", + "sgsv": "Safety duplicated in Svalbard", + "storage": "Type of Germplasm storage" + } + } +} \ No newline at end of file diff --git a/src/accessions/ui/BrowsePage.tsx b/src/accessions/ui/BrowsePage.tsx index bcab95d1..846e0f26 100644 --- a/src/accessions/ui/BrowsePage.tsx +++ b/src/accessions/ui/BrowsePage.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; import { parse } from 'query-string'; @@ -40,7 +41,7 @@ class BrowsePage extends BrowsePageTemplate { } public render() { - const { paged, filterCode, currentTab } = this.props; + const { paged, filterCode, currentTab, t} = this.props; const renderAccession = (s: Accession, index: number) => { return ; @@ -50,11 +51,11 @@ class BrowsePage extends BrowsePageTemplate { }> - + @@ -62,15 +63,15 @@ class BrowsePage extends BrowsePageTemplate { tab={ currentTab } actions={ - - - + + + } > - Accessions - Overview - Map + { t('accessions.tab.data') } + { t('accessions.tab.overview') } + { t('accessions.tab.map') } @@ -107,4 +108,4 @@ const mapDispatchToProps = (dispatch) => bindActionCreators({ }, dispatch); -export default connect(mapStateToProps, mapDispatchToProps)(BrowsePage); +export default translate()(connect(mapStateToProps, mapDispatchToProps)(BrowsePage)); diff --git a/src/accessions/ui/DisplayPage.tsx b/src/accessions/ui/DisplayPage.tsx index edc894f8..c2b40f8f 100644 --- a/src/accessions/ui/DisplayPage.tsx +++ b/src/accessions/ui/DisplayPage.tsx @@ -95,7 +95,7 @@ class BrowsePage extends React.Component { return ( - + { stillLoading ? :
@@ -105,12 +105,12 @@ class BrowsePage extends React.Component { - Accession: { accession.accessionNumber } + { t('accessions.common.modelName') }: { accession.accessionNumber }
- { isChecked ? `Remove ${accession.accessionNumber} from my list` : `Add ${accession.accessionNumber} to my list` } + { isChecked ? t('accessions.public.p.display.removeFromMyList', {accessionNumber: accession.accessionNumber}) : t('accessions.public.p.display.addToMyList', {accessionNumber: accession.accessionNumber}) } } input={ { @@ -123,85 +123,85 @@ class BrowsePage extends React.Component { } > - { accession.doi && } - { accession.accessionNumber } - + { accession.doi && } + { accession.accessionNumber } + { accession.institute.fullName } - { accession.institute.code } - - { accession.countryOfOrigin && { } } - { accession.sampStat && { t(`accession.sampleStatus.${accession.sampStat}`) } } - { accession.storage && accession.storage.length > 0 && + { accession.institute.code } + + { accession.countryOfOrigin && { } } + { accession.sampStat && { t(`accessions.common.sampleStatus.${accession.sampStat}`) } } + { accession.storage && accession.storage.length > 0 && { accession.storage.map((storage, i) => ( -
{ t(`accession.storage.${storage}`) }
+
{ t(`accessions.common.storage.${storage}`) }
)) }
} - { t(`accession.available.${accession.available}`) } - { t(`accession.mlsStatus.${accession.mlsStatus}`) } - { accession.donorCode } - { accession.donorNumb } + { t(`accessions.common.available.${accession.available}`) } + { t(`accessions.common.mlsStatus.${accession.mlsStatus}`) } + { accession.donorCode } + { accession.donorNumb } - { accession.duplSite && accession.duplSite.length > 0 && + { accession.duplSite && accession.duplSite.length > 0 && { accession.duplSite.map((duplSite, i) => (
{ duplSite }
)) }
} - { accession.acceUrl && } + { accession.acceUrl && }
- + - { accession.taxonomy.genus } - + { accession.taxonomy.genus } + { accession.taxonomy.species } { ' — ' } View { `${accession.taxonomy.genus} ${accession.taxonomy.species}` } at { accession.institute.code } - - { accession.crop && } - { accession.cropName } + + { accession.crop && } + { accession.cropName } { (accession.donorCode || (accession.aliases && accession.aliases.length > 0)) && - + - { accession.donorCode && { accession.donorNumb } { accession.donorCode } } + { accession.donorCode && { accession.donorNumb } { accession.donorCode } } { accession.aliases && accession.aliases.map((alias) => ( - { alias.name } { alias.usedBy } + { alias.name } { alias.usedBy } )) } } { accession.coll && - + - { accession.countryOfOrigin && { } } - { accession.coll.collDate && } + { accession.countryOfOrigin && { } } + { accession.coll.collDate && } { accession.coll && [ 'collMissId', 'collNumb', 'collSite', 'collSrc' ] .filter((prop) => accession.coll[prop] !== null).map((prop) => ( - { accession.coll[prop] } + { accession.coll[prop] } )) } { accession.coll && [ 'collCode', 'collName' ] .filter((prop) => accession.coll[prop].length).map((prop) => ( - { accession.coll[prop] } + { accession.coll[prop] } )) } { accession.geo && [ 'latitude', 'longitude', 'datum', 'method', 'uncertainty', 'elevation' ] .filter((prop) => accession.geo[prop] !== null).map((prop) => ( - { accession.geo[prop] } + { accession.geo[prop] } )) } @@ -220,7 +220,7 @@ class BrowsePage extends React.Component { } - { accession.remarks && accession.remarks.length > 0 && + { accession.remarks && accession.remarks.length > 0 && { accession.remarks && accession.remarks.map((remark) => ( { remark.remark } @@ -228,14 +228,14 @@ class BrowsePage extends React.Component { } - { pdci && } + { pdci && } - + - { `urn:uuid:${accession.uuid}` } - - - + { `urn:uuid:${accession.uuid}` } + + + @@ -243,17 +243,17 @@ class BrowsePage extends React.Component { { datasets && datasets.length > 0 && ({ title: 'Dataset', value: })) } + propertiesList={ datasets.map((dataset) => ({ title: 'dataset.common.modelName', value: })) } /> } { subsets && subsets.length > 0 && ({ title: 'Subset', value: })) } + propertiesList={ subsets.map((subset) => ({ title: 'subset.common.modelName', value: })) } /> } diff --git a/src/accessions/ui/MapPage.tsx b/src/accessions/ui/MapPage.tsx index aea6cab6..84bc1bee 100644 --- a/src/accessions/ui/MapPage.tsx +++ b/src/accessions/ui/MapPage.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import {connect} from 'react-redux'; +import {translate} from 'react-i18next'; import {withStyles} from '@material-ui/core/styles'; import {bindActionCreators} from 'redux'; import { loadAccessionsMapInfo } from 'accessions/actions/public'; @@ -23,6 +24,7 @@ interface IMapPageProps extends React.ClassAttributes { classes: any; filterCode: string; loadAccessionsMapInfo: any; + t: any; } const styles = (theme) => ({ @@ -70,7 +72,7 @@ class BrowsePage extends React.Component { public render() { const position = [30, 0]; - const { mapInfo, currentTab, classes, filterCode } = this.props; + const { mapInfo, currentTab, classes, filterCode, t } = this.props; if (! mapInfo) { return ; @@ -81,7 +83,7 @@ class BrowsePage extends React.Component { return ( - + { } > - Accessions - Overview - Map + { t('accessions.tab.data') } + { t('accessions.tab.overview') } + { t('accessions.tab.map') } bindActionCreators({ loadAccessionsMapInfo, }, dispatch); -export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(BrowsePage)); +export default translate()(connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(BrowsePage))); diff --git a/src/accessions/ui/OverviewPage.tsx b/src/accessions/ui/OverviewPage.tsx index 17ee5f40..8e4bcc3e 100644 --- a/src/accessions/ui/OverviewPage.tsx +++ b/src/accessions/ui/OverviewPage.tsx @@ -129,7 +129,7 @@ class BrowsePage extends React.Component { } withFooter > - + { } > - Accessions - Overview - Map + { t('accessions.tab.data') } + { t('accessions.tab.overview') } + { t('accessions.tab.map') } { { overviewsTerms && overviewsTerms.get('institute.code') && overviewsTerms.get('institute.code').length > 2 && - ({title: term.term, value: filterByTerm('holder.code', term, term.count) })) } title={ t(`accession.overview.institute code`) } small/> + ({title: term.term, value: filterByTerm('holder.code', term, term.count) })) } title={ t(`accessions.common.overview.institute code`) } small/> } { overviewsTerms && overviewsTerms.get('institute.country.code3') && overviewsTerms.get('institute.country.code3').length > 2 && - ({title: term.term, value: filterByTerm('holder.country.iso3', term, term.count) })) } title={ t(`accession.overview.institute country code3`) } small/> + ({title: term.term, value: filterByTerm('holder.country.iso3', term, term.count) })) } title={ t(`accessions.common.overview.institute country code3`) } small/> } { overviewsTerms && overviewsTerms.get('crop.shortName') && overviewsTerms.get('crop.shortName').length > 2 && - ({title: term.term, value: filterByTerm('crop', term, term.count)})) } title={ t(`accession.overview.crop shortName`) } small/> + ({title: term.term, value: filterByTerm('crop', term, term.count)})) } title={ t(`accessions.common.overview.crop shortName`) } small/> } { overviewsTerms && overviewsTerms.get('cropName') && overviewsTerms.get('cropName').length > 2 && - ({title: term.term, value: term.count })) } title={ t(`accession.overview.cropName`) } small/> + ({title: term.term, value: term.count })) } title={ t(`accessions.common.overview.cropName`) } small/> } { overviewsTerms && overviewsTerms.get('taxonomy.genus') && overviewsTerms.get('taxonomy.genus').length > 2 && - ({title: term.term, value: filterByTerm('taxa.genus', term, term.count) })) } title={ t(`accession.overview.taxonomy genus`) } small/> + ({title: term.term, value: filterByTerm('taxa.genus', term, term.count) })) } title={ t(`accessions.common.overview.taxonomy genus`) } small/> } { overviewsTerms && overviewsTerms.get('taxonomy.genusSpecies') && overviewsTerms.get('taxonomy.genusSpecies').length > 2 && - ({title: term.term, value: term.count })) } title={ t(`accession.overview.taxonomy genusSpecies`) } small/> + ({title: term.term, value: term.count })) } title={ t(`accessions.common.overview.taxonomy genusSpecies`) } small/> } { overviewsTerms && overviewsTerms.get('sampStat') && overviewsTerms.get('sampStat').length > 2 && term.term !== 'other').map((term) => ({title: t(`accession.sampleStatus.${term.term}`), value: filterByTerm('sampStat', term, term.count) })) } title={ t(`accession.overview.sampStat`) } small/> + .filter((term) => term.term !== 'other').map((term) => ({title: t(`accessions.common.sampleStatus.${term.term}`), value: filterByTerm('sampStat', term, term.count) })) } title={ t(`accessions.common.overview.sampStat`) } small/> } { overviewsTerms && overviewsTerms.get('storage') && overviewsTerms.get('storage').length > 2 && - ({title: t(`accession.storage.${term.term}`), value: filterByTerm('storage', term, term.count) })) } title={ t(`accession.overview.storage`) } small/> + ({title: t(`accessions.common.storage.${term.term}`), value: filterByTerm('storage', term, term.count) })) } title={ t(`accessions.common.overview.storage`) } small/> } { overviewsTerms && overviewsTerms.get('countryOfOrigin.code3') && overviewsTerms.get('countryOfOrigin.code3').length > 2 && - ({title: term.term, value: filterByTerm('origin.iso3', term, term.count)})) } title={ t(`accession.overview.countryOfOrigin code3`) } small/> + ({title: term.term, value: filterByTerm('origin.iso3', term, term.count)})) } title={ t(`accessions.common.overview.countryOfOrigin code3`) } small/> } { overviewsTerms && overviewsTerms.get('donorCode') && overviewsTerms.get('donorCode').length > 2 && - ({title: term.term, value: term.count })) } title={ t(`accession.overview.donorCode`) } small/> + ({title: term.term, value: term.count })) } title={ t(`accessions.common.overview.donorCode`) } small/> } { overviewsTerms && overviewsTerms.get('duplSite') && overviewsTerms.get('duplSite').length > 2 && - ({title: term.term, value: term.count })) } title={ t(`accession.overview.duplSite`) } small/> + ({title: term.term, value: term.count })) } title={ t(`accessions.common.overview.duplSite`) } small/> } { overviewsTerms && overviewsTerms.get('breederCode') && overviewsTerms.get('breederCode').length > 2 && - ({title: term.term, value: term.count })) } title={ t(`accession.overview.breederCode`) } small/> + ({title: term.term, value: term.count })) } title={ t(`accessions.common.overview.breederCode`) } small/> } { overviewsTerms && overviewsTerms.get('mlsStatus') && overviewsTerms.get('mlsStatus').length > 2 && - ({title: term.term === '1' ? 'Yes' : 'No', value: filterByTerm('mlsStatus', term, term.count) })) } title={ t(`accession.overview.mlsStatus`) } small/> + ({title: term.term === '1' ? 'Yes' : 'No', value: filterByTerm('mlsStatus', term, term.count) })) } title={ t(`accessions.common.overview.mlsStatus`) } small/> } { overviewsTerms && overviewsTerms.get('available') && overviewsTerms.get('available').length > 2 && - ({title: term.term === '1' ? 'Yes' : 'No', value: filterByTerm('available', term, term.count) })) } title={ t(`accession.overview.available`) } small/> + ({title: term.term === '1' ? 'Yes' : 'No', value: filterByTerm('available', term, term.count) })) } title={ t(`accessions.common.overview.available`) } small/> } { overviewsTerms && overviewsTerms.get('sgsv') && overviewsTerms.get('sgsv').length > 2 && - ({title: term.term === '1' ? 'Yes' : 'No', value: filterByTerm('sgsv', term, term.count) })) } title={ t(`accession.overview.sgsv`) } small/> + ({title: term.term === '1' ? 'Yes' : 'No', value: filterByTerm('sgsv', term, term.count) })) } title={ t(`accessions.common.overview.sgsv`) } small/> } diff --git a/src/accessions/ui/c/AccessionCard.tsx b/src/accessions/ui/c/AccessionCard.tsx index 26153d33..a6f4486b 100644 --- a/src/accessions/ui/c/AccessionCard.tsx +++ b/src/accessions/ui/c/AccessionCard.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import {connect} from 'react-redux'; +import {translate} from 'react-i18next'; import {bindActionCreators} from 'redux'; import { withStyles } from '@material-ui/core/styles'; @@ -23,8 +24,8 @@ const styles = (theme) => ({ }, }); -const AccessionCard = ({ accession, classes, index, addAccessionToMyList, removeAccessionFromMyList, accessions, ...other }: - { accession: Accession, classes: any, index?: number, addAccessionToMyList: (uuid: string) => void , removeAccessionFromMyList: (uuid: string) => void, accessions: any} & React.ClassAttributes) => { +const AccessionCard = ({ accession, classes, index, addAccessionToMyList, removeAccessionFromMyList, accessions, t, ...other }: + { accession: Accession, classes: any, index?: number, addAccessionToMyList: (uuid: string) => void , removeAccessionFromMyList: (uuid: string) => void, accessions: any, t: any} & React.ClassAttributes) => { const isChecked = accession && accessions && accessions.includes(accession.uuid); let touchTimer; @@ -57,7 +58,7 @@ const AccessionCard = ({ accession, classes, index, addAccessionToMyList, remove { /* { accession.crop && } */ } { accession.countryOfOrigin && ` • ${accession.countryOfOrigin.name}` } - { isChecked ? `Remove` : `+ Add to my list` } + { isChecked ? t('common:action.remove') : `+ ${t('accessions.public.c.accessionCard.addToMyList')}` }
@@ -89,4 +90,4 @@ const mapDispatchToProps = (dispatch) => bindActionCreators({ removeAccessionFromMyList, }, dispatch); -export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(AccessionCard)); +export default translate()(connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(AccessionCard))); diff --git a/src/accessions/ui/c/Filters.tsx b/src/accessions/ui/c/Filters.tsx index 3ef04b66..e90c0d4d 100644 --- a/src/accessions/ui/c/Filters.tsx +++ b/src/accessions/ui/c/Filters.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import { reduxForm } from 'redux-form'; +import {translate} from 'react-i18next'; import { ACCESSION_FILTERFORM } from 'accessions/constants'; @@ -12,49 +13,50 @@ import StringArrFilter from 'ui/common/filter/StringArrFilter'; import Accession from 'model/accession/Accession'; import DateFilter from 'ui/common/filter/DateFilter'; -const AccessionFilters = ({handleSubmit, initialValues, initialize, ...other}) => { +const AccessionFilters = ({handleSubmit, initialValues, initialize, t, ...other}) => { // console.log('AccessionFilters', initialValues); return ( - - + + - - - - + + + + - - + + - - - - + + + + - - - - - + + + + + - + - + - - - - + + + + + ); }; -export default reduxForm({ +export default translate()(reduxForm({ enableReinitialize: true, destroyOnUnmount: false, form: ACCESSION_FILTERFORM, -})(AccessionFilters); +})(AccessionFilters)); diff --git a/src/accessions/ui/c/PdciTable.tsx b/src/accessions/ui/c/PdciTable.tsx index bbda668f..5430f302 100644 --- a/src/accessions/ui/c/PdciTable.tsx +++ b/src/accessions/ui/c/PdciTable.tsx @@ -58,10 +58,10 @@ class PdciTable extends React.Component {
- { t('accession.pdciScore', {score: pdci.score}) } + { t('accessions.public.c.pdciTable.pdciScore', {score: pdci.score}) } { ' ' } - Read about Passport Data Completeness Index + { t('accessions.public.c.pdciTable.readPDCI') }
diff --git a/src/actions/serverInfo.ts b/src/actions/serverInfo.ts index 9bdd34b1..7d2856ae 100644 --- a/src/actions/serverInfo.ts +++ b/src/actions/serverInfo.ts @@ -27,7 +27,7 @@ export const checkSoftwareVersion = () => (dispatch, getState) => { const currentSoftVersion: string = window.softwareCommit; if (currentSoftVersion !== softwareVersion) { - dispatch(showSnackbar('New version is available', PageReloadButton)); + dispatch(showSnackbar('common:label.newVersionAvailable', PageReloadButton)); } setTimeout(() => dispatch(checkSoftwareVersion()), delay); diff --git a/src/cms/translations.json b/src/cms/translations.json new file mode 100644 index 00000000..6e0602a4 --- /dev/null +++ b/src/cms/translations.json @@ -0,0 +1,15 @@ +{ + "menu": { + "about": "About Genesys", + "contact": "Contact us", + "what-is-genesys": "What is Genesys?", + "history-of-genesys": "History of Genesys", + "newsletter": "Genesys Newsletter", + "faq": "Frequently asked questions", + "how-to-use-genesys": "How to use Genesys?", + "disclaimer": "Disclaimer", + "terms": "Terms and Conditions of Use", + "copying": "Copyright policy", + "privacy": "Privacy policy" + } +} diff --git a/src/cms/ui/c/MenuStepper.tsx b/src/cms/ui/c/MenuStepper.tsx index e6716430..6ac37c1d 100644 --- a/src/cms/ui/c/MenuStepper.tsx +++ b/src/cms/ui/c/MenuStepper.tsx @@ -40,7 +40,7 @@ class MenuStepper extends React.Component { { menu.items.map((menuItem: MenuItem) => (
- { t(`content.${menuItem.text}`) } + { t(`cms.${menuItem.text}`) }
)) diff --git a/src/crop/translations.json b/src/crop/translations.json new file mode 100644 index 00000000..f7e95eb4 --- /dev/null +++ b/src/crop/translations.json @@ -0,0 +1,50 @@ +{ + "public": { + "c": { + "cropCard": { + "originalName": "Original name", + "registered": "Registered" + }, + "cropSelector": { + "helper": "Contact helpdesk@genesys-pgr.org to register additional crops." + } + }, + "p": { + "display": { + "title": "Crop details", + "generalInformation": "General information", + "otherNames": "Other names" + }, + "browse": { + "title": "Crop list", + "subTitle": "Genesys crops directory", + "createCrop": "Create crop" + } + } + }, + "admin": { + "c": { + "cropForm": { + "cropCode": "Crop code", + "cropTitle": "Crop title", + "otherNames": "Other names", + "version": "Version: {{version: numeric}}", + "alreadyInUse": "Already in use" + } + }, + "p": { + "edit": { + "onDelete": { + "message": "Delete crop '{{cropName, lowercase}}'?", + "description": "Note, deleting any crop causes mayhem." + } + } + } + }, + "common": { + "modelName": "Crop", + "modelName_plural": "Crops", + "menu": "Crops", + "accessionsInGenesys": "Accessions in genesys" + } +} \ No newline at end of file diff --git a/src/crop/ui/BrowsePage.tsx b/src/crop/ui/BrowsePage.tsx index 781b4f62..0724261b 100644 --- a/src/crop/ui/BrowsePage.tsx +++ b/src/crop/ui/BrowsePage.tsx @@ -1,6 +1,7 @@ import * as React from 'react'; import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; +import { translate } from 'react-i18next'; // Actions import {createCrop} from 'crop/actions/admin'; @@ -19,6 +20,7 @@ import Authorize from 'ui/common/authorized/Authorize'; interface IBrowsePageProps extends React.ClassAttributes { crops: CropDetails[]; + t: any; createCrop: any; } @@ -30,17 +32,17 @@ class BrowsePage extends React.Component { } public render() { - const {crops} = this.props; + const {crops, t} = this.props; return ( - + - }/> + }/> - { crops && crops.sort((a, b) => a.name.localeCompare(b.name)).map((crop) => ) } + { crops && crops.sort((a, b) => a.name.localeCompare(b.name)).map((crop) => ) } @@ -58,4 +60,4 @@ const mapDispatchToProps = (dispatch) => bindActionCreators({ }, dispatch); -export default connect(mapStateToProps, mapDispatchToProps)(BrowsePage); +export default connect(mapStateToProps, mapDispatchToProps)(translate()(BrowsePage)); diff --git a/src/crop/ui/DisplayPage.tsx b/src/crop/ui/DisplayPage.tsx index 1bbdf4e7..b750b2fb 100644 --- a/src/crop/ui/DisplayPage.tsx +++ b/src/crop/ui/DisplayPage.tsx @@ -60,7 +60,7 @@ interface IDisplayPageProps extends React.ClassAttributes { cropDetails: CropDetails; crops: Crop[]; shortName: string; - i18n: any; + t: any; classes: any; applyFilters: any; } @@ -87,12 +87,12 @@ class DisplayPage extends React.Component { } public render() { - const { cropDetails, shortName, classes } = this.props; + const { cropDetails, shortName, classes, t } = this.props; const crop = cropDetails; return ( - + { !crop || crop.shortName !== shortName ? () : { cropDetails.blurb && cropDetails.blurb.body && @@ -100,17 +100,17 @@ class DisplayPage extends React.Component {
} - + - + - + - ({title: otherName})) } propertyItemProps={ {keepEmpty: true, small: true} }/> + ({title: otherName})) } propertyItemProps={ {keepEmpty: true, small: true} }/> } diff --git a/src/crop/ui/EditPage.tsx b/src/crop/ui/EditPage.tsx index fa5d45f7..28173361 100644 --- a/src/crop/ui/EditPage.tsx +++ b/src/crop/ui/EditPage.tsx @@ -3,6 +3,7 @@ import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; import Grid from '@material-ui/core/Grid'; import Paper from '@material-ui/core/Paper'; +import { translate } from 'react-i18next'; import {log} from 'utilities/debug'; import confirm from 'utilities/confirmAlert'; @@ -23,6 +24,7 @@ interface ICropEditPageProps extends React.ClassAttributes { deleteCrop: (crop: Crop) => void; navigateTo: (path: string, query?: string) => void; crop: Crop; + t: any; } class CropEditPage extends React.Component { @@ -37,12 +39,12 @@ class CropEditPage extends React.Component { } private onDelete = () => { - const {crop, deleteCrop} = this.props; + const {crop, deleteCrop, t} = this.props; - confirm(`Delete crop '${crop.name}'?`, { - description: `Note, deleting any crop causes mayhem.`, - confirmLabel: 'Delete', - abortLabel: 'Cancel', + confirm(t('crop.admin.p.edit.onDelete.message', {cropName: crop.name}), { + description: t('crop.admin.p.edit.onDelete.description'), + confirmLabel: t('common:action.delete'), + abortLabel: t('common:action.cancel'), }).then(() => { deleteCrop(crop); }).catch(() => { @@ -59,7 +61,7 @@ class CropEditPage extends React.Component { } public render() { - const {shortName, cropNames} = this.props; + const {shortName, cropNames, t} = this.props; let {crop} = this.props; if (!crop && !shortName) { @@ -76,7 +78,7 @@ class CropEditPage extends React.Component { - + @@ -99,4 +101,4 @@ const mapDispatchToProps = (dispatch) => bindActionCreators({ navigateTo, }, dispatch); -export default connect(mapStateToProps, mapDispatchToProps)(CropEditPage); +export default connect(mapStateToProps, mapDispatchToProps)(translate()(CropEditPage)); diff --git a/src/crop/ui/c/CropCard.tsx b/src/crop/ui/c/CropCard.tsx index a9f74ef4..4e627ace 100644 --- a/src/crop/ui/c/CropCard.tsx +++ b/src/crop/ui/c/CropCard.tsx @@ -74,7 +74,7 @@ const CropImage = ({classes, crop}: { classes: any, crop: CropDetails}) => { ); }; -const CropCard = ({crop, classes, compact = false, edit = false, ...other}: { crop: CropDetails, classes?: any, compact?: boolean, edit?: boolean }) => { +const CropCard = ({crop, classes, compact = false, edit = false, t, ...other}: { crop: CropDetails, classes?: any, compact?: boolean, edit?: boolean, t: any }) => { if (!crop) { return null; } @@ -98,15 +98,15 @@ const CropCard = ({crop, classes, compact = false, edit = false, ...other}: { cr }/> - { crop.name } - - + { crop.name } + + - + diff --git a/src/crop/ui/c/CropForm.tsx b/src/crop/ui/c/CropForm.tsx index 74e3de24..c9074f8c 100644 --- a/src/crop/ui/c/CropForm.tsx +++ b/src/crop/ui/c/CropForm.tsx @@ -20,9 +20,12 @@ const onRemoveString = (item) => { log('Removing string', item); }; -const CropForm = ({error, handleSubmit, initialValues, onDelete, cropNames}) => { +const CropForm = ({error, handleSubmit, initialValues, onDelete, cropNames, t}) => { - const notInUse = (value) => !value || cropNames && Object.keys(cropNames).filter((cropShortName) => cropNames[cropShortName].indexOf(value) !== -1 && cropShortName !== initialValues.shortName).length === 0 ? undefined : 'Already in use'; + const notInUse = (value) => !value || cropNames && + Object.keys(cropNames).filter((cropShortName) => cropNames[cropShortName].indexOf(value) !== -1 && cropShortName !== initialValues.shortName).length === 0 + ? undefined + : t('crop.admin.c.cropForm.alreadyInUse'); const stringField = (otherName, index, fields, itemLabel) => ( @@ -30,22 +33,22 @@ const CropForm = ({error, handleSubmit, initialValues, onDelete, cropNames}) => return (
- { initialValues.version >= 0 ?
Version: { initialValues.version }
: null } + { initialValues.version >= 0 ?
{ t(`crop.admin.c.cropForm.version`, {version: initialValues.version}) }
: null } - - + +

Other names

- +
{ error && { error } }
- - { (initialValues._permissions && initialValues._permissions.delete) && } - + + { (initialValues._permissions && initialValues._permissions.delete) && } +
); @@ -56,7 +59,7 @@ const validate = (values) => { const otherNamesError = []; values.otherNames.map((otherName, index, array) => { if (array.indexOf(otherName) !== index) { - otherNamesError[index] = 'Duplicate'; + otherNamesError[index] = 'Duplicate'; // TODO add t for errorMsg } }); return { otherNames : otherNamesError }; diff --git a/src/crop/ui/c/CropSelector.tsx b/src/crop/ui/c/CropSelector.tsx index 46a696dd..9b5608d4 100644 --- a/src/crop/ui/c/CropSelector.tsx +++ b/src/crop/ui/c/CropSelector.tsx @@ -54,7 +54,7 @@ const renderRadioButton = (input, code) => ( const CropSelector = ({t, crops, label, single, fields, input}: ICropSelectorProps) => crops && ( { label } - { t('m.crop.helper') } + { t('crop.public.c.cropSelector.helper') } { crops.sort((a, b) => a.name.localeCompare(b.name)).map((crop: Crop) => ( diff --git a/src/institutes/translations.json b/src/institutes/translations.json new file mode 100644 index 00000000..6068adde --- /dev/null +++ b/src/institutes/translations.json @@ -0,0 +1,46 @@ +{ + "public": { + "c": { + "instituteCard": { + "accessionsInGenesys": "Accessions in Genesys: {{count, numeric}}" + } + }, + "f": { + "title": "Filter institutes", + "instituteName": "Institute name" + }, + "p": { + "browse": { + "title": "WIEWS Institutes", + "subTitle": "Explore wiews institutes" + }, + "display": { + "title": "Institute details", + "type": "Type", + "webLink": "Web link", + "about": "About", + "representedCrops": "Most represented Crops", + "representedCropNames": "Most represented Crop names", + "representedGenera": "Most represented Genera", + "representedSpecies": "Most represented Species", + "lastUpdates": "Last updates of passport data", + "PDCI": "PDCI: Passport data complex index", + "readPDCI": "Read about Passport Data Completeness Index", + "pdciScore": "Average PDCI score for {{count, number}} accessions is {{avg, number}}, with minimum score of {{min, number}} and maximum score of {{max, number}}." + } + } + }, + "sort": { + "instituteCode": "Institute code" + }, + "common": { + "modelName": "Institute", + "modelName_plural": "Institutes", + "menu": "Institutes", + "stats": "Institute", + "stats_plural": "Institutes", + "instCode": "INSTCODE", + "instituteCode": "Institute code", + "accessionsInGenesys": "Accessions in Genesys" + } +} \ No newline at end of file diff --git a/src/institutes/ui/BrowsePage.tsx b/src/institutes/ui/BrowsePage.tsx index 4d00155b..4349c65f 100644 --- a/src/institutes/ui/BrowsePage.tsx +++ b/src/institutes/ui/BrowsePage.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; import { parse } from 'query-string'; +import { translate } from 'react-i18next'; // Actions import {applyFilters, loadInstitutesPage, updateRoute} from 'institutes/actions/public'; @@ -38,7 +39,7 @@ class BrowsePage extends BrowsePageTemplate { } public render() { - const { paged } = this.props; + const { paged, t } = this.props; const renderInstitute = (s: FaoInstitute, index: number) => { return ; @@ -46,15 +47,15 @@ class BrowsePage extends BrowsePageTemplate { return ( + }> - + @@ -90,4 +91,4 @@ const mapDispatchToProps = (dispatch) => bindActionCreators({ }, dispatch); -export default connect(mapStateToProps, mapDispatchToProps)(BrowsePage); +export default connect(mapStateToProps, mapDispatchToProps)(translate()(BrowsePage)); diff --git a/src/institutes/ui/DisplayPage.tsx b/src/institutes/ui/DisplayPage.tsx index 01f881be..fbba7457 100644 --- a/src/institutes/ui/DisplayPage.tsx +++ b/src/institutes/ui/DisplayPage.tsx @@ -98,7 +98,7 @@ class DisplayPage extends React.Component { return ( - + { stillLoading ? :
@@ -108,22 +108,22 @@ class DisplayPage extends React.Component { - { institute.details.code } - { institute.details.type } - { } + { institute.details.code } + { institute.details.type } + { } { institute.details.url && - + { institute.details.url } } - + { institute.blurb && institute.blurb.body && - +
@@ -131,10 +131,10 @@ class DisplayPage extends React.Component { } { institute.details.latitude !== null && institute.details.longitude !== null && - + - { institute.details.latitude } - { institute.details.longitude } + { institute.details.latitude } + { institute.details.longitude } { { cropShortNameOverview && cropShortNameOverview.terms && cropShortNameOverview.terms.length > 0 && ({title: term.term, value: term.count})) } small /> @@ -159,7 +159,7 @@ class DisplayPage extends React.Component { { cropNameOverview && cropNameOverview.terms && cropNameOverview.terms.length > 0 && ({title: term.term, value: term.count})) } small > @@ -178,7 +178,7 @@ class DisplayPage extends React.Component { { taxonomyGenusOverview && taxonomyGenusOverview.terms && taxonomyGenusOverview.terms.length > 0 && ({title: term.term, value: term.count})) } small > @@ -197,7 +197,7 @@ class DisplayPage extends React.Component { { taxonomyGenusSpeciesOverview && taxonomyGenusSpeciesOverview.terms && taxonomyGenusSpeciesOverview.terms.length > 0 && ({title: term.term, value: term.count})) } small > @@ -217,7 +217,7 @@ class DisplayPage extends React.Component { { institute.lastUpdates && institute.lastUpdates.length > 0 && - + { institute.lastUpdates.map((lastUpdate) => ( { } { institute.pdciStats && institute.pdciStats.histogram && institute.pdciStats.histogram.length > 0 && - + ({key: i % 2 === 0 ? i / 2 : '', value: item })) }/> -

{ t('institute.Institute PDCI score', { count: institute.pdciStats.count, avg: institute.pdciStats.avg, min: institute.pdciStats.min, max: institute.pdciStats.max }) }

- Read about Passport Data Completeness Index +

{ t('institutes.public.p.display.pdciScore', { count: institute.pdciStats.count, avg: institute.pdciStats.avg, min: institute.pdciStats.min, max: institute.pdciStats.max }) }

+ { t('institutes.public.p.display.readPDCI') }
} diff --git "a/src/institutes/ui/\321\201/Filters.tsx" "b/src/institutes/ui/\321\201/Filters.tsx" index 3451ef34..4a791aaf 100644 --- "a/src/institutes/ui/\321\201/Filters.tsx" +++ "b/src/institutes/ui/\321\201/Filters.tsx" @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import { reduxForm } from 'redux-form'; import { INSTITUTE_FILTERFORM } from 'institutes/constants'; @@ -9,25 +10,25 @@ import StringFilter from 'ui/common/filter/StringFilter'; import StringArrFilter from 'ui/common/filter/StringArrFilter'; import BooleanFilter from 'ui/common/filter/BooleanFilter'; -const AccessionFilters = ({handleSubmit, initialValues, initialize, ...other}) => { +const AccessionFilters = ({handleSubmit, initialValues, initialize, t, ...other}) => { // console.log('AccessionFilters', initialValues); return ( - - + + - - - + + + - - + + ); }; -export default reduxForm({ +export default translate()(reduxForm({ enableReinitialize: true, form: INSTITUTE_FILTERFORM, -})(AccessionFilters); +})(AccessionFilters)); diff --git "a/src/institutes/ui/\321\201/InstituteCard.tsx" "b/src/institutes/ui/\321\201/InstituteCard.tsx" index 675b1036..4aa8eae8 100644 --- "a/src/institutes/ui/\321\201/InstituteCard.tsx" +++ "b/src/institutes/ui/\321\201/InstituteCard.tsx" @@ -5,7 +5,7 @@ import FaoInstitute from 'model/genesys/FaoInstitute'; import {InstituteLink} from 'ui/genesys/Links'; import Card, {CardContent, CardActions} from 'ui/common/Card'; import SciName from 'ui/genesys/SciName'; -import Number from 'ui/common/Number'; +import { translate } from 'react-i18next'; const styles = (theme) => ({ firstRow: { @@ -13,7 +13,7 @@ const styles = (theme) => ({ }, }); -const InstituteCard = ({ institute, classes, index, ...other }: { institute: FaoInstitute, classes: any, index?: number } & React.ClassAttributes) => { +const InstituteCard = ({ institute, classes, index, t, ...other }: { institute: FaoInstitute, classes: any, index?: number, t: any } & React.ClassAttributes) => { return ( @@ -30,7 +30,7 @@ const InstituteCard = ({ institute, classes, index, ...other }: { institute: Fao { institute.country && ` • ${institute.country.name}` } - { institute.accessionCount && Accessions in Genesys: } + { institute.accessionCount && { t('institutes.public.c.instituteCard.accessionsInGenesys', {count: institute.accessionCount}) } }
@@ -48,4 +48,4 @@ const InstituteCard = ({ institute, classes, index, ...other }: { institute: Fao ); }; -export default withStyles(styles)(InstituteCard); +export default translate()(withStyles(styles)(InstituteCard)); diff --git a/src/list/translations.json b/src/list/translations.json new file mode 100644 index 00000000..6739898d --- /dev/null +++ b/src/list/translations.json @@ -0,0 +1,15 @@ +{ + "public": { + "p": { + "browse": { + "title": "Selected accessions", + "subTitle": "As you explore the millions of accessions held in Genesys, you can create your own list to keep track of the results of your search. Your selections are stored here so you can return to them at any time.", + "sendRequest": "Send request", + "noAccessions": "You have not added any accessions to the list." + } + } + }, + "common": { + "menu": "My List" + } +} \ No newline at end of file diff --git a/src/list/ui/BrowsePage.tsx b/src/list/ui/BrowsePage.tsx index 0ab2821f..74e76e80 100644 --- a/src/list/ui/BrowsePage.tsx +++ b/src/list/ui/BrowsePage.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; @@ -13,6 +14,7 @@ import navigateTo from 'actions/navigation'; interface IMyListPageProps extends React.ClassAttributes { myList: any[]; navigateTo: any; + t: any; } class MyListPage extends React.Component { @@ -47,23 +49,24 @@ class MyListPage extends React.Component { public render() { const {accessions} = this.state; + const {t} = this.props; return ( { accessions && accessions.length > 0 ? (
} + title={ `${accessions.length} ${t('accessions.common.modelName', {count: accessions.length})}` } + buttons={ } /> { accessions.map((accession, index) =>
) }
) : ( - + ) }
@@ -81,4 +84,4 @@ const mapDispatchToProps = (dispatch) => bindActionCreators({ }, dispatch); -export default connect(mapStateToProps, mapDispatchToProps)(MyListPage); +export default translate()(connect(mapStateToProps, mapDispatchToProps)(MyListPage)); diff --git a/src/model/accession/Accession.ts b/src/model/accession/Accession.ts index e0a5d101..5468a772 100644 --- a/src/model/accession/Accession.ts +++ b/src/model/accession/Accession.ts @@ -65,39 +65,39 @@ class Accession { }; public static SAMPSTAT: { [key: number]: string; } = { - 100: 'accession.sampleStatus.100', - 110: 'accession.sampleStatus.110', - 120: 'accession.sampleStatus.120', - 130: 'accession.sampleStatus.130', - 200: 'accession.sampleStatus.200', - 300: 'accession.sampleStatus.300', - 400: 'accession.sampleStatus.400', - 410: 'accession.sampleStatus.410', - 411: 'accession.sampleStatus.411', - 412: 'accession.sampleStatus.412', - 413: 'accession.sampleStatus.413', - 414: 'accession.sampleStatus.414', - 415: 'accession.sampleStatus.415', - 416: 'accession.sampleStatus.416', - 420: 'accession.sampleStatus.420', - 421: 'accession.sampleStatus.421', - 422: 'accession.sampleStatus.422', - 423: 'accession.sampleStatus.423', - 500: 'accession.sampleStatus.500', - 600: 'accession.sampleStatus.600', - 999: 'accession.sampleStatus.999', + 100: 'accessions.common.sampleStatus.100', + 110: 'accessions.common.sampleStatus.110', + 120: 'accessions.common.sampleStatus.120', + 130: 'accessions.common.sampleStatus.130', + 200: 'accessions.common.sampleStatus.200', + 300: 'accessions.common.sampleStatus.300', + 400: 'accessions.common.sampleStatus.400', + 410: 'accessions.common.sampleStatus.410', + 411: 'accessions.common.sampleStatus.411', + 412: 'accessions.common.sampleStatus.412', + 413: 'accessions.common.sampleStatus.413', + 414: 'accessions.common.sampleStatus.414', + 415: 'accessions.common.sampleStatus.415', + 416: 'accessions.common.sampleStatus.416', + 420: 'accessions.common.sampleStatus.420', + 421: 'accessions.common.sampleStatus.421', + 422: 'accessions.common.sampleStatus.422', + 423: 'accessions.common.sampleStatus.423', + 500: 'accessions.common.sampleStatus.500', + 600: 'accessions.common.sampleStatus.600', + 999: 'accessions.common.sampleStatus.999', }; public static STORAGE: { [key: number]: string; } = { - 10: 'accession.storage.10', - 11: 'accession.storage.11', - 12: 'accession.storage.12', - 13: 'accession.storage.13', - 20: 'accession.storage.20', - 30: 'accession.storage.30', - 40: 'accession.storage.40', - 50: 'accession.storage.50', - 99: 'accession.storage.99', + 10: 'accessions.common.storage.10', + 11: 'accessions.common.storage.11', + 12: 'accessions.common.storage.12', + 13: 'accessions.common.storage.13', + 20: 'accessions.common.storage.20', + 30: 'accessions.common.storage.30', + 40: 'accessions.common.storage.40', + 50: 'accessions.common.storage.50', + 99: 'accessions.common.storage.99', }; } diff --git a/src/model/genesys/FaoInstitute.ts b/src/model/genesys/FaoInstitute.ts index cff16b96..f497c98c 100644 --- a/src/model/genesys/FaoInstitute.ts +++ b/src/model/genesys/FaoInstitute.ts @@ -32,7 +32,7 @@ class FaoInstitute { }; public static SORT_OPTIONS = { - code: { label: 'Institute code', direction: 'ASC'}, + code: { label: 'institutes.sort.instituteCode', direction: 'ASC'}, accessionCount1: { property: 'accessionCount', label: 'Collection size (largest first)', direction: 'DESC' }, accessionCount2: { property: 'accessionCount', label: 'Collection size (smallest first)', direction: 'ASC' }, }; diff --git a/src/model/request/RequestInfo.ts b/src/model/request/RequestInfo.ts index 75fd1a45..a43bf243 100644 --- a/src/model/request/RequestInfo.ts +++ b/src/model/request/RequestInfo.ts @@ -7,7 +7,7 @@ class RequestInfo { } export const PURPOSE_TYPES = [ - {value: '1', label: 'Research for food and agriculture'}, - {value: '0', label: 'Other (please elaborate in Notes field)'}, + {value: '1', label: 'requests.common.purposeType.1'}, + {value: '0', label: 'requests.common.purposeType.0'}, ]; export default RequestInfo; diff --git a/src/model/user/User.ts b/src/model/user/User.ts index 019167b8..5a740d3b 100644 --- a/src/model/user/User.ts +++ b/src/model/user/User.ts @@ -2,12 +2,12 @@ import { UuidModel } from 'model/common.model'; class User extends UuidModel { public static USERROLES: { [key: string]: any; } = { - USER: 'User', - ADMINISTRATOR: 'Administrator', - EVERYONE: 'Everyone', - VALIDATEDUSER: 'Validated user', - VETTEDUSER: 'Vetted user', - CONTENTMANAGER: 'Content manager', + USER: 'user.common.role.USER', + ADMINISTRATOR: 'user.common.role.ADMINISTRATOR', + EVERYONE: 'user.common.role.EVERYONE', + VALIDATEDUSER: 'user.common.role.VALIDATEDUSER', + VETTEDUSER: 'user.common.role.VETTEDUSER', + CONTENTMANAGER: 'user.common.role.CONTENTMANAGER', }; public clazz: string = 'org.genesys2.server.model.impl.User'; diff --git a/src/repository/translations.json b/src/repository/translations.json new file mode 100644 index 00000000..14ce3fc6 --- /dev/null +++ b/src/repository/translations.json @@ -0,0 +1,59 @@ +{ + "admin": { + "p": { + "editFile": { + "formTitle": "Update file metadata" + }, + "imageGallery": { + "toFolder": "To folder", + "deleteGallery": "Delete gallery", + "deleteGalleryAlert": "Gallery at {{folderPath, string}} could not be deleted." + }, + "repositoryBrowser": { + "viewGallery": "View gallery", + "createGallery": "Create gallery", + "createGalleryAlert": "Image gallery at {{folderPath, string}} could not be created.", + "deleteFolder": "Delete folder", + "deleteFolderAlert": "Folder {{folderPath, string}} could not be deleted." + } + }, + "dialog": { + "updateFolder": { + "updateDialogTitle": "Update folder metadata", + "updateBtn": "Edit folder" + }, + "createFolder": { + "createDialogTitle": "Create new folder", + "createBtn": "Create new folder" + } + }, + "c": { + "common": { + "path": "Path", + "registered": "Registered" + }, + "fileCard": { + "originalName": "Original name" + }, + "fileForm": { + "subject": "Subject", + "rightsHolder": "Rights Holder", + "originalUrl": "Original URL", + "license": "License", + "extent": "Extent", + "creator": "Creator", + "contentType": "Content Type", + "bibliographicCitation": "Bibliographic Citation", + "accessRights": "Access Rights" + }, + "folderCrumbs": { + "root": "ROOT" + }, + "folderForm": { + "form": { + "name": "Folder name" + } + } + } + } +} \ No newline at end of file diff --git a/src/repository/ui/CreateFolderDialog.tsx b/src/repository/ui/CreateFolderDialog.tsx index 61c479a5..8680f674 100644 --- a/src/repository/ui/CreateFolderDialog.tsx +++ b/src/repository/ui/CreateFolderDialog.tsx @@ -62,12 +62,12 @@ class CreateFolderDialog extends React.Component const { classes, variant = 'raised', t} = this.props; return ( - + { this.state.open && - { t(`p.admin.repository.folder.createDialogTitle`) } + { t(`repository.admin.dialog.createFolder.createDialogTitle`) } - + } diff --git a/src/repository/ui/EditFilePage.tsx b/src/repository/ui/EditFilePage.tsx index 3b93ba70..fd91f6e6 100644 --- a/src/repository/ui/EditFilePage.tsx +++ b/src/repository/ui/EditFilePage.tsx @@ -58,11 +58,11 @@ class EditFilePage extends React.Component { return file === null ? () : (
- + - + diff --git a/src/repository/ui/ImageGalleryPage.tsx b/src/repository/ui/ImageGalleryPage.tsx index a68f090f..27e84957 100644 --- a/src/repository/ui/ImageGalleryPage.tsx +++ b/src/repository/ui/ImageGalleryPage.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import { translate } from 'react-i18next'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import { withStyles } from '@material-ui/core/styles'; @@ -18,7 +19,7 @@ import Button from '@material-ui/core/Button'; import { navigateTo } from 'actions/navigation'; import confirmAlert from 'utilities/confirmAlert'; import ImageGalleryView from 'repository/ui/c/ImageGalleryView'; -import { FolderCrumbs } from 'repository/ui/c/FolderCrumbs'; +import FolderCrumbs from 'repository/ui/c/FolderCrumbs'; // import Grid from '@material-ui/core/Grid'; @@ -78,13 +79,13 @@ class ImageGalleryPage extends React.Component { } protected deleteGallery = (e) => { - const { removeGallery, navigateTo, folderPath } = this.props; + const { removeGallery, navigateTo, folderPath, t } = this.props; removeGallery(folderPath).then((result) => { if (result) { navigateTo(`/admin/repository/f${folderPath}/`); } else { - confirmAlert(

Gallery at { folderPath } could not be deleted.

); + confirmAlert(

{ t('repository.admin.p.imageGallery.deleteGalleryAlert', {folderPath}) }

); } }); } @@ -96,7 +97,7 @@ class ImageGalleryPage extends React.Component { public render() { - const { gallery, root, path } = this.props; + const { gallery, root, path, t } = this.props; const stillLoading: boolean = !gallery; @@ -107,8 +108,8 @@ class ImageGalleryPage extends React.Component {
} buttons={ - - { gallery && gallery._permissions.delete && } + + { gallery && gallery._permissions.delete && } { gallery && gallery._permissions.manage && } } /> @@ -139,4 +140,4 @@ const mapDispatchToProps = (dispatch) => bindActionCreators({ navigateTo, }, dispatch); -export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(ImageGalleryPage)); +export default translate()(connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(ImageGalleryPage))); diff --git a/src/repository/ui/RepositoryBrowser.tsx b/src/repository/ui/RepositoryBrowser.tsx index db25afad..98309839 100644 --- a/src/repository/ui/RepositoryBrowser.tsx +++ b/src/repository/ui/RepositoryBrowser.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import { connect } from 'react-redux'; +import { translate } from 'react-i18next'; import { bindActionCreators } from 'redux'; import { withStyles } from '@material-ui/core/styles'; import { normalize } from 'path'; @@ -20,7 +21,7 @@ import RepositoryFolder from 'model/repository/RepositoryFolder'; import Button from '@material-ui/core/Button'; import { navigateTo } from 'actions/navigation'; import confirmAlert from 'utilities/confirmAlert'; -import { FolderCrumbs } from './c/FolderCrumbs'; +import FolderCrumbs from './c/FolderCrumbs'; import Grid from '@material-ui/core/Grid'; import FileUploader from 'ui/common/file-uploader'; @@ -83,13 +84,13 @@ class RepositoryBrowser extends React.Component { } protected deleteFolder = (e) => { - const { deleteFolder, navigateTo, folderPath } = this.props; + const { deleteFolder, navigateTo, folderPath, t } = this.props; deleteFolder(folderPath).then((result) => { if (result) { navigateTo('..'); } else { - confirmAlert(

Folder { folderPath } could not be deleted.

); + confirmAlert(

{ t('repository.admin.p.repositoryBrowser.deleteFolderAlert', {folderPath}) }

); } }); } @@ -103,13 +104,13 @@ class RepositoryBrowser extends React.Component { } protected createGallery = (e) => { - const { createGallery, navigateTo, folder, folderPath } = this.props; + const { createGallery, navigateTo, folder, folderPath, t } = this.props; createGallery(folderPath, folder.folder.name).then((result) => { if (result) { navigateTo(`/admin/repository/g${folderPath}/`); } else { - confirmAlert(

Image gallery at { folderPath } could not be created.

); + confirmAlert(

{ t('repository.admin.p.repositoryBrowser.createGalleryAlert', {folderPath}) }

); } }); } @@ -121,7 +122,7 @@ class RepositoryBrowser extends React.Component { public render() { - const { folder, root, path } = this.props; + const { folder, root, path, t } = this.props; const parentFolder = new RepositoryFolder(); parentFolder.path = '..'; @@ -137,8 +138,9 @@ class RepositoryBrowser extends React.Component { } buttons={ { ! folder.folder ? null : - folder.gallery ? : } - { folder.folder && folder.folder._permissions.delete && } + folder.gallery ? : + } + { folder.folder && folder.folder._permissions.delete && } { (! folder.folder || (folder.folder && folder.folder._permissions.create)) && } { folder.folder && folder.folder._permissions.write && } { folder.folder && folder.folder._permissions.manage && } @@ -181,4 +183,4 @@ const mapDispatchToProps = (dispatch) => bindActionCreators({ navigateTo, }, dispatch); -export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(RepositoryBrowser)); +export default translate()(connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(RepositoryBrowser))); diff --git a/src/repository/ui/UpdateFolderDialog.tsx b/src/repository/ui/UpdateFolderDialog.tsx index 15d8b1f0..ffcc3a0a 100644 --- a/src/repository/ui/UpdateFolderDialog.tsx +++ b/src/repository/ui/UpdateFolderDialog.tsx @@ -59,10 +59,10 @@ class UpdateFolderDialog extends React.Component const { t, classes, variant = 'raised', folder} = this.props; return ( - + { this.state.open && - { t(`p.admin.repository.folder.updateDialogTitle`) } + { t(`repository.admin.dialog.updateFolder.updateDialogTitle`) } diff --git a/src/repository/ui/c/FileCard.tsx b/src/repository/ui/c/FileCard.tsx index ec4f056a..8600f68e 100644 --- a/src/repository/ui/c/FileCard.tsx +++ b/src/repository/ui/c/FileCard.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import { translate } from 'react-i18next'; // Models import RepositoryFile from 'model/repository/RepositoryFile'; @@ -72,8 +73,8 @@ const style = (theme) => ({ }); /*tslint:enable*/ -const FileCard = ({file, classes, compact = false, edit = false, deleteFile, editFile, ...other}: - { file: RepositoryFile, classes?: any, compact?: boolean, edit?: boolean, deleteFile: (uuid: string) => any, editFile: (uuid: string) => any }) => { +const FileCard = ({file, classes, compact = false, edit = false, deleteFile, editFile, t, ...other}: + { file: RepositoryFile, classes?: any, compact?: boolean, edit?: boolean, deleteFile: (uuid: string) => any, editFile: (uuid: string) => any, t: any }) => { if (!file) { return null; @@ -97,17 +98,17 @@ const FileCard = ({file, classes, compact = false, edit = false, deleteFile, edi title={ { file.originalFilename } } action={
- editFile(file.uuid) } title="Edit"/> - deleteFile(file.uuid) } title="Delete"/> + editFile(file.uuid) } title="common:action.edit"/> + deleteFile(file.uuid) } title="common:action.delete"/> { file && file._permissions.manage && }
} /> - { file.originalFilename } - - + { file.originalFilename } + + @@ -115,4 +116,4 @@ const FileCard = ({file, classes, compact = false, edit = false, deleteFile, edi ); }; -export default withStyles(style)(FileCard); +export default translate()(withStyles(style)(FileCard)); diff --git a/src/repository/ui/c/FileForm.tsx b/src/repository/ui/c/FileForm.tsx index 349e2ea7..4fbbdfc1 100644 --- a/src/repository/ui/c/FileForm.tsx +++ b/src/repository/ui/c/FileForm.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import { translate } from 'react-i18next'; import {Field, reduxForm} from 'redux-form'; import {TextField} from 'ui/common/text-field'; import Validators from 'utilities/Validators'; @@ -20,70 +21,70 @@ class FileForm extends React.Component {
{ error &&
{ error }
} - - + + ); } } -export default reduxForm({ +export default translate()(reduxForm({ form: EDIT_FILE_FORM, enableReinitialize: true, -})(FileForm); +})(FileForm)); diff --git a/src/repository/ui/c/FolderCard.tsx b/src/repository/ui/c/FolderCard.tsx index d57815b6..b3745d87 100644 --- a/src/repository/ui/c/FolderCard.tsx +++ b/src/repository/ui/c/FolderCard.tsx @@ -40,9 +40,9 @@ const FolderCard = ({root = '.', folder, classes, compact = false, edit = false, { folder.name } } /> - { folder.path } - - + { folder.path } + + diff --git a/src/repository/ui/c/FolderCrumbs.tsx b/src/repository/ui/c/FolderCrumbs.tsx index 29d601fa..6a2d4c53 100644 --- a/src/repository/ui/c/FolderCrumbs.tsx +++ b/src/repository/ui/c/FolderCrumbs.tsx @@ -1,7 +1,8 @@ import * as React from 'react'; +import { translate } from 'react-i18next'; import { Link } from 'react-router-dom'; -export function FolderCrumbs({ path, root = '/', disabled = false }: { path: string, root?: string, disabled?: boolean }) { +const FolderCrumbs = ({ path, root = '/', disabled = false, t }: { path: string, root?: string, disabled?: boolean, t: any }) => { if (path) { const parts: string[] = path.split('/').filter((part) => part.length > 0); @@ -9,12 +10,14 @@ export function FolderCrumbs({ path, root = '/', disabled = false }: { path: str // console.log(`Path ${disabled} parts path=${path}`, parts, len); return ( - { disabled || len === 0 ? 'ROOT' : ROOT } / + { disabled || len === 0 ? t('repository.admin.c.folderCrumbs.root') : { t('repository.admin.c.folderCrumbs.root') } } / { parts && parts.map((part, index) => { disabled || index === len - 1 ? part : { part } } /) } ); } else { return null; } -} +}; + +export default translate()(FolderCrumbs); diff --git a/src/repository/ui/c/FolderForm.tsx b/src/repository/ui/c/FolderForm.tsx index 8b21b980..dc986532 100644 --- a/src/repository/ui/c/FolderForm.tsx +++ b/src/repository/ui/c/FolderForm.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import { translate } from 'react-i18next'; import {Field, reduxForm} from 'redux-form'; import {TextField} from 'ui/common/text-field'; import Validators from 'utilities/Validators'; @@ -21,33 +22,33 @@ class FolderForm extends React.Component {
: } { error &&
{ error }
} - - + + ); } } -export default reduxForm({ +export default translate()(reduxForm({ form: EDIT_FOLDER_FORM, enableReinitialize: true, -})(FolderForm); +})(FolderForm)); diff --git a/src/repository/ui/c/ImageGalleryView.tsx b/src/repository/ui/c/ImageGalleryView.tsx index 9ffb9c33..5a2e1055 100644 --- a/src/repository/ui/c/ImageGalleryView.tsx +++ b/src/repository/ui/c/ImageGalleryView.tsx @@ -56,9 +56,9 @@ const ImageGalleryView = ({imageGallery, classes, compact = false, edit = false, - { imageGallery.folder } - - + { imageGallery.folder } + + diff --git a/src/requests/translations.json b/src/requests/translations.json new file mode 100644 index 00000000..6ef6077a --- /dev/null +++ b/src/requests/translations.json @@ -0,0 +1,65 @@ +{ + "public": { + "p": { + "stepper": { + "accessionsList": { + "title": "Out of {{count, number}} accessions listed, {{available, number}} are known to be available for distribution.", + "stepName": "Review list of material" + }, + "confirm": { + "instructions": "Once you push **submit request** button your request will be validated.\n\nCheck your email and also check your SPAM folder for a validation message from Genesys.\n\nThe email address provided will be checked against ITPGRFA's Easy-SMTA database.", + "stepName": "Finalize and submit" + }, + "requestInfo": { + "stepName": "Personal information", + "email": "Your e-mail address as registered in Easy-SMTA", + "preacceptSMTA": "SMTA/MTA acceptance:", + "preacceptSMTATrue": "I will accept the terms and conditions of SMTA/MTA", + "preacceptSMTAFalse": "I will NOT accept the terms and conditions of SMTA/MTA", + "purposeType": "Specify use of material:", + "notes": "Additional notes to submit with your request" + } + } + } + }, + "admin": { + "p": { + "browse": { + "title": "{{totalElements, number}} requests for PGR material" + }, + "display": { + "title": "Request from {{email, string}}", + "sendValidationEmail": "Send validation email", + "validateRequest": "Validate Request", + "recheckPID": "Recheck PID", + "requestInformation": "Request information", + "recipientPIDInformation": "Recipient PID information", + "shippingAddress": "Shipping address", + "notes": "Notes", + "dispatchedTo": "Dispatched to", + "requestedAccessionIds": "Requested accession ids" + } + } + }, + "common": { + "modelMame": "Request", + "modelMame_plural": "Requests", + "preacceptSMTA": "Preaccept SMTA", + "stateLabel": "State", + "state": { + "0": "Not validated", + "1": "Validated", + "2": "Dispatched" + }, + "typeLabel": "Type", + "type": { + "in": "Individual", + "or": "Organizational" + }, + "purposeTypeLabel": "Purpose type", + "purposeType": { + "0": "Other (please elaborate in Notes field)", + "1": "Research for food and agriculture" + } + } +} \ No newline at end of file diff --git a/src/requests/ui/admin/BrowsePage.tsx b/src/requests/ui/admin/BrowsePage.tsx index 216a5fb7..d4f3a6bf 100644 --- a/src/requests/ui/admin/BrowsePage.tsx +++ b/src/requests/ui/admin/BrowsePage.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; @@ -27,7 +28,7 @@ class BrowsePage extends BrowsePageTemplate { } public render() { - const { paged } = this.props; + const { paged, t } = this.props; const renderRequest = (r: MaterialRequest, index: number) => { return ; @@ -35,7 +36,7 @@ class BrowsePage extends BrowsePageTemplate { return (
- + { ! paged ? : bindActionCreators({ }, dispatch); -export default connect(mapStateToProps, mapDispatchToProps)(BrowsePage); +export default translate()(connect(mapStateToProps, mapDispatchToProps)(BrowsePage)); diff --git a/src/requests/ui/admin/DisplayPage.tsx b/src/requests/ui/admin/DisplayPage.tsx index 89a15509..6980b9f8 100644 --- a/src/requests/ui/admin/DisplayPage.tsx +++ b/src/requests/ui/admin/DisplayPage.tsx @@ -51,63 +51,63 @@ class DisplayPage extends React.Component { return request === null ? () : (
- sendValidationEmail(request.uuid) }/> - validateRequest(request.uuid) }/> - recheckPid(request.uuid) }/> + sendValidationEmail(request.uuid) }/> + validateRequest(request.uuid) }/> + recheckPid(request.uuid) }/>
} /> { request.body && - + - { request.email } - { t(`request.state.${request.state}`) } - - { request.body.pid && { t(`request.type.${request.body.pid.type}`) } } - { request.body.requestInfo && { t(`request.purposeType.${request.body.requestInfo.purposeType}`) } } - { request.body.requestInfo && { request.body.requestInfo.preacceptSMTA ? 'Yes' : 'No' } } - { request.body.requestInfo && { request.body.requestInfo.notes } } - { request.body.accessionIds.reduce((id, acc) => `${acc}, ${id}`) } + { request.email } + { t(`requests.common.state.${request.state}`) } + + { request.body.pid && { t(`requests.common.type.${request.body.pid.type}`) } } + { request.body.requestInfo && { t(`requests.common.purposeType.${request.body.requestInfo.purposeType}`) } } + { request.body.requestInfo && { request.body.requestInfo.preacceptSMTA ? 'Yes' : 'No' } } + { request.body.requestInfo && { request.body.requestInfo.notes } } + { request.body.accessionIds.reduce((id, acc) => `${acc}, ${id}`) } { request.body.pid && request.body.pid.type === 'in' && - + - { request.body.pid.name } - { request.body.pid.surname } - - { request.body.pid.country } - { request.body.pid.telephone } - { request.body.pid.email } + { request.body.pid.name } + { request.body.pid.surname } + + { request.body.pid.country } + { request.body.pid.telephone } + { request.body.pid.email } } { request.body.pid && request.body.pid.type === 'or' && - + - { request.body.pid.orgName } - - { request.body.pid.orgCountry } + { request.body.pid.orgName } + + { request.body.pid.orgCountry } } { request.body.pid && request.body.pid.shipAddrFlag !== 's' && - + - - { request.body.pid.shipCountry } - { request.body.pid.shipTelephone } + + { request.body.pid.shipCountry } + { request.body.pid.shipTelephone } } { request.subrequests && request.subrequests.length > 0 && - + { request.subrequests.map((sub) => ( diff --git a/src/requests/ui/admin/c/RequestCard.tsx b/src/requests/ui/admin/c/RequestCard.tsx index fa73d948..9eaeac82 100644 --- a/src/requests/ui/admin/c/RequestCard.tsx +++ b/src/requests/ui/admin/c/RequestCard.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import {withStyles} from '@material-ui/core/styles'; import MaterialRequest from 'model/request/MaterialRequest'; @@ -12,13 +13,13 @@ const styles = () => ({ }, }); -const RequestCard = ({request, classes, index, ...other}: { request: MaterialRequest, classes: any, index?: number } & React.ClassAttributes) => { +const RequestCard = ({request, classes, index, t, ...other}: { request: MaterialRequest, classes: any, index?: number, t: any } & React.ClassAttributes) => { if (! request) { console.log('Null request for RequestCard'); return null; } - const requestStates = [{label: 'NOT VALIDATED', color: 'orange'}, {label: 'VALIDATED', color: '#06aced'}, {label: 'DISPATCHED', color: 'green'}]; + const requestStates = [{label: t('requests.common.state.0'), color: 'orange'}, {label: t('requests.common.state.1'), color: '#06aced'}, {label: t('requests.common.state.2'), color: 'green'}]; return ( @@ -40,11 +41,11 @@ const RequestCard = ({request, classes, index, ...other}: { request: MaterialReq } - { request.body.accessionIds.length } accessions + { `${request.body.accessionIds.length} ${t('accessions.common.modelName', {count: request.body.accessionIds.length})}` }
); }; -export default withStyles(styles)(RequestCard); +export default translate()(withStyles(styles)(RequestCard)); diff --git a/src/requests/ui/request-stepper/steps.ts b/src/requests/ui/request-stepper/steps.ts index 3508c5ce..41c6b617 100644 --- a/src/requests/ui/request-stepper/steps.ts +++ b/src/requests/ui/request-stepper/steps.ts @@ -5,21 +5,21 @@ import ConfirmStep from 'requests/ui/request-stepper/steps/confirm'; const steps = [ { id: 1, - name: 'Review list of material', + name: 'requests.public.p.stepper.accessionsList.stepName', path: '/create', component: AccessionsListStep, exact: true, }, { id: 2, - name: 'Personal information', + name: 'requests.public.p.stepper.requestInfo.stepName', path: '/create/request-info', component: RequestInfoStep, exact: true, }, { id: 3, - name: 'Finalize and submit', + name: 'requests.public.p.stepper.confirm.stepName', path: '/create/submit', component: ConfirmStep, exact: true, diff --git a/src/requests/ui/request-stepper/steps/accessionsList/AccessionsList.tsx b/src/requests/ui/request-stepper/steps/accessionsList/AccessionsList.tsx index 4e72655a..4dd383eb 100644 --- a/src/requests/ui/request-stepper/steps/accessionsList/AccessionsList.tsx +++ b/src/requests/ui/request-stepper/steps/accessionsList/AccessionsList.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import withStyles from '@material-ui/core/styles/withStyles'; // model @@ -18,10 +19,10 @@ const countAvailable = (accessions: Accession[]) => { return accessions.filter((accession) => accession.available && accession.institute.allowMaterialRequests).length; }; -const AccessionsList = ({accessions, classes}) => ( +const AccessionsList = ({accessions, classes, t}) => (
{ accessions.map((accession, index) => (
@@ -36,5 +37,5 @@ const AccessionsList = ({accessions, classes}) => (
); -export default withStyles(style)(AccessionsList); +export default translate()(withStyles(style)(AccessionsList)); diff --git a/src/requests/ui/request-stepper/steps/confirm/index.tsx b/src/requests/ui/request-stepper/steps/confirm/index.tsx index aba03811..3250b735 100644 --- a/src/requests/ui/request-stepper/steps/confirm/index.tsx +++ b/src/requests/ui/request-stepper/steps/confirm/index.tsx @@ -31,7 +31,7 @@ class ConfirmStep extends StepperTemplate { const { t } = this.props; return (
- +
); } diff --git a/src/requests/ui/request-stepper/steps/requestInfo/c/PurposeTypeRadioGroup.tsx b/src/requests/ui/request-stepper/steps/requestInfo/c/PurposeTypeRadioGroup.tsx index f0d3daf1..6b7bdd3e 100644 --- a/src/requests/ui/request-stepper/steps/requestInfo/c/PurposeTypeRadioGroup.tsx +++ b/src/requests/ui/request-stepper/steps/requestInfo/c/PurposeTypeRadioGroup.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import FormControlLabel from '@material-ui/core/FormControlLabel'; import FormLabel from '@material-ui/core/FormLabel'; @@ -7,9 +8,9 @@ import Radio from '@material-ui/core/Radio'; import RadioGroup from '@material-ui/core/RadioGroup'; import {PURPOSE_TYPES} from 'model/request/RequestInfo'; -const PurposeTypeRadioGroup = ({input, meta, classes, formLabel, labelTrue, labelFalse, ...rest}) => ( +const PurposeTypeRadioGroup = ({input, meta, classes, formLabel, t, ...rest}) => ( - Specify use of material: + { formLabel } } /> )) @@ -32,4 +33,4 @@ const PurposeTypeRadioGroup = ({input, meta, classes, formLabel, labelTrue, labe ); -export default PurposeTypeRadioGroup; +export default translate()(PurposeTypeRadioGroup); diff --git a/src/requests/ui/request-stepper/steps/requestInfo/c/RequestInfoForm.tsx b/src/requests/ui/request-stepper/steps/requestInfo/c/RequestInfoForm.tsx index 646f076e..fd79e91d 100644 --- a/src/requests/ui/request-stepper/steps/requestInfo/c/RequestInfoForm.tsx +++ b/src/requests/ui/request-stepper/steps/requestInfo/c/RequestInfoForm.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import {Field, reduxForm} from 'redux-form'; // Actions import {receiveRequestInfo} from 'requests/actions/public'; @@ -14,17 +15,18 @@ import PurposeTypeRadioGroup from './PurposeTypeRadioGroup'; interface IPersonalInfoFormProps extends React.ClassAttributes { handleSubmit: any; + t: any; } class RequestInfoForm extends React.Component { public render() { - const {handleSubmit} = this.props; + const {handleSubmit, t} = this.props; return (
{ { } -export default reduxForm({ +export default translate()(reduxForm({ form: REQUEST_INFO_FORM, onSubmit: (values, dispatch) => dispatch(receiveRequestInfo(values)), enableReinitialize: true, -})(RequestInfoForm); +})(RequestInfoForm)); diff --git a/src/subsets/translations.json b/src/subsets/translations.json new file mode 100644 index 00000000..f386b0ef --- /dev/null +++ b/src/subsets/translations.json @@ -0,0 +1,113 @@ +{ + "public": { + "c": { + "subsetCard": { + "crops": "Crops", + "numberOfAccessions": "Number of accessions", + "institute": "Institute", + "license": "License", + "creationDate": "Creation date", + "source": "Source" + }, + "subsetDisplay": { + "subsetCreators": "Subset creators" + } + }, + "f": { + "filterTitle": "Filter subsets", + "textSearch": "Text search", + "title": "Title", + "titlePlaceholder": "International", + "description": "Description", + "descriptionPlaceholder": "Subset description", + "institute": "Institute", + "institutePlaceholder": "MEX002", + "crop": "Crop" + }, + "p": { + "browse": { + "title": "Subset browser", + "subTitle": "Explore curated sets of subsets" + }, + "display": { + "title": "Subset {{subsetTitle: string}}" + } + } + }, + "dashboard": { + "c": { + "dashboard": { + "no": "No.", + "publisher": "Publisher", + "status": "Status" + } + }, + "menu": { + "subsets": "Subsets", + "listSubsets": "List subsets", + "createSubsets": "Create subset" + }, + "p": { + "stepper": { + "accessionList": { + "stepName": "List of accessions", + "instructions": "INSTRUCTIONS FOR USE", + "Subset template": "Subset template", + "detailedInstructions1": "Use \"Acccessions\" sheet from template: ", + "detailedInstructions2": "Do not change header name in the template:", + "detailedInstructions3": "Fill the template with the information of the accessions, save it.", + "detailedInstructions4": "Copy and paste the table from Excel into the text field below.", + "listOfAccessions": "List of accessions described in the dataset", + "pasteData": "Paste accessions data here (comma separated)", + "accessionListCount": "Accession list: {{count, numeric}} rows" + }, + "basicInfo": { + "stepName": "Basic information", + "subsetTitle": "Subset title", + "instituteCode": "Institute code", + "subsetDescription": "Subset description", + "subsetDescriptionPlaceholder": "An abstract, short or long description of the resource. Descriptive details improves discoverability of the resource.", + "crops": "Crops", + "rights": "Rights", + "creationDate": "Creation date", + "source": "Source" + }, + "creators": { + "stepName": "Subset creators", + "Role": "Role: ", + "fullName": "Full name", + "fullNamePlaceholder": "Jane A. Doe", + "institutionalAffiliation": "Institutional affiliation", + "institutionalAffiliationPlaceholder": "Institutional affiliation", + "email": "Email address", + "emailPlaceholder": "name@domain.com", + "phone": "Phone number", + "phonePlaceholder": "+1 555 1231 Ext. 13", + "fax": "Fax", + "faxPlaceholder": "+1 555 1231 Ext. 42", + "address": "Address", + "addressPlaceholder": "Address", + "addSubsetCreator": "Add subset creator" + }, + "review": { + "stepName": "Review and publish" + } + } + } + }, + "common": { + "modelName": "Subset", + "modelName_plural": "Subsets", + "menu": "Subsets", + "stats": "Subset", + "stats_plural": "Subsets", + "creators": { + "role": { + "MANAGER": "Data manager", + "DIGITIZER": "Data digitizer", + "COLLECTOR": "Data collector", + "CURATOR": "Data curator" + } + } + } +} \ No newline at end of file diff --git a/src/subsets/ui/BrowsePage.tsx b/src/subsets/ui/BrowsePage.tsx index 880dc89c..d2c9dbd4 100644 --- a/src/subsets/ui/BrowsePage.tsx +++ b/src/subsets/ui/BrowsePage.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import { translate } from 'react-i18next'; import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; import { parse } from 'query-string'; @@ -39,7 +40,7 @@ class BrowsePage extends BrowsePageTemplate { } public render() { - const { paged } = this.props; + const { paged, t } = this.props; const renderSubset = (s: Subset) => { return ; @@ -47,15 +48,15 @@ class BrowsePage extends BrowsePageTemplate { return ( + }> - + @@ -91,4 +92,4 @@ const mapDispatchToProps = (dispatch) => bindActionCreators({ }, dispatch); -export default connect(mapStateToProps, mapDispatchToProps)(BrowsePage); +export default translate()(connect(mapStateToProps, mapDispatchToProps)(BrowsePage)); diff --git a/src/subsets/ui/DisplayPage.tsx b/src/subsets/ui/DisplayPage.tsx index 50dbacd7..b6388a88 100644 --- a/src/subsets/ui/DisplayPage.tsx +++ b/src/subsets/ui/DisplayPage.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import { translate } from 'react-i18next'; import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; // Actions @@ -15,7 +16,7 @@ import ContentHeaderWithButton from 'ui/common/heading/ContentHeaderWithButton'; import ActionButton from 'ui/common/buttons/ActionButton'; import SubsetDisplay from './c/SubsetDisplay'; -interface IBrowsePageProps extends React.ClassAttributes { +interface IDisplayPageProps extends React.ClassAttributes { uuid: string; subset: Subset; userRole: string[]; @@ -23,9 +24,10 @@ interface IBrowsePageProps extends React.ClassAttributes { loadSubset: any; navigateTo: any; unpublishSubset: (subset: Subset) => void; + t: any; } -class BrowsePage extends React.Component { +class DisplayPage extends React.Component { protected static needs = [ ({ params: { uuid } }) => { @@ -41,7 +43,7 @@ class BrowsePage extends React.Component { } } - constructor(props: IBrowsePageProps, context: any) { + constructor(props: IDisplayPageProps, context: any) { super(props, context); } @@ -53,14 +55,14 @@ class BrowsePage extends React.Component { } public render() { - const { error, subset, uuid, userRole } = this.props; + const { error, subset, uuid, userRole, t } = this.props; const stillLoading: boolean = ! error && (! subset || (uuid && subset && subset.uuid !== uuid)); const isActionsActive: boolean = userRole.findIndex((role) => role === 'ROLE_ADMINISTRATOR') !== -1 || (subset && subset.state === PublishState.REVIEWING); return ( - : '' } /> + : '' } /> { stillLoading ? : @@ -89,4 +91,4 @@ const mapDispatchToProps = (dispatch) => bindActionCreators({ }, dispatch); -export default connect(mapStateToProps, mapDispatchToProps)(BrowsePage); +export default translate()(connect(mapStateToProps, mapDispatchToProps)(DisplayPage)); diff --git a/src/subsets/ui/c/Filters.tsx b/src/subsets/ui/c/Filters.tsx index 0705e8e0..8c08ef49 100644 --- a/src/subsets/ui/c/Filters.tsx +++ b/src/subsets/ui/c/Filters.tsx @@ -9,16 +9,16 @@ import StringFilter from 'ui/common/filter/StringFilter'; import StringArrFilter from 'ui/common/filter/StringArrFilter'; import CropFilter from 'crop/ui/c/CropFilter'; -const SubsetFilters = ({handleSubmit, initialValues, initialize, ...other}) => { +const SubsetFilters = ({handleSubmit, initialValues, initialize, t, ...other}) => { // console.log('SubsetFilters', initialValues); return ( - - - - - + + + + + - + diff --git a/src/subsets/ui/c/SubsetCard.tsx b/src/subsets/ui/c/SubsetCard.tsx index 737ed5d8..6540ca4c 100644 --- a/src/subsets/ui/c/SubsetCard.tsx +++ b/src/subsets/ui/c/SubsetCard.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import { translate } from 'react-i18next'; import Subset from 'model/subset/Subset'; import { SubsetLink, InstituteLink } from 'ui/genesys/Links'; @@ -11,18 +12,18 @@ import { Properties, PropertiesItem } from 'ui/common/Properties'; import CropChips from 'crop/ui/c/CropChips'; import McpdDate from 'ui/common/time/McpdDate'; -const SubsetCard = ({subset, complete = false, ...other}: { subset: Subset, complete?: boolean } & React.ClassAttributes) => { +const SubsetCard = ({subset, complete = false, t, ...other}: { subset: Subset, complete?: boolean, t: any } & React.ClassAttributes) => { return ( } /> - { subset.crops && subset.crops.length > 0 && } - - { subset.institute.fullName } - { complete && } - { complete && subset.source && } + { subset.crops && subset.crops.length > 0 && } + + { subset.institute.fullName } + { complete && } + { complete && subset.source && } @@ -35,4 +36,4 @@ const SubsetCard = ({subset, complete = false, ...other}: { subset: Subset, comp ); }; -export default SubsetCard; +export default translate()(SubsetCard); diff --git a/src/subsets/ui/c/SubsetDisplay.tsx b/src/subsets/ui/c/SubsetDisplay.tsx index 7c2a7c54..a6706b02 100644 --- a/src/subsets/ui/c/SubsetDisplay.tsx +++ b/src/subsets/ui/c/SubsetDisplay.tsx @@ -42,7 +42,7 @@ class DetailInfo extends React.Component { log('Waiting for subset.'); return null; } - + // TODO sometimes creator can be null return (
@@ -50,10 +50,10 @@ class DetailInfo extends React.Component { { subset.creators && ({ - title: t(`subset.creator.role.${creator.role}`), + title: t(`subsets.creator.role.${creator.role}`), value: ({ creator.fullName }{ creator.institutionalAffiliation && { creator.institutionalAffiliation } }), })) } diff --git a/src/subsets/ui/dashboard/DashboardPage.tsx b/src/subsets/ui/dashboard/DashboardPage.tsx index 2eb9731b..5ffd44b3 100644 --- a/src/subsets/ui/dashboard/DashboardPage.tsx +++ b/src/subsets/ui/dashboard/DashboardPage.tsx @@ -30,12 +30,12 @@ const sortOptions = { }; const tableHeaderProps = [ - {title: 'No.', width: '10px'}, - {title: 'Title', width: '40%'}, - {title: 'Publisher', width: null}, - {title: 'Created', width: null}, - {title: 'Modified', width: null}, - {title: 'Status', width: '90px'}, + {title: 'subsets.dashboard.c.dashboard.no', width: '10px'}, + {title: 'common:label.title', width: '40%'}, + {title: 'subsets.dashboard.c.dashboard.publisher', width: null}, + {title: 'common:label.created', width: null}, + {title: 'common:label.modified', width: null}, + {title: 'subsets.dashboard.c.dashboard.status', width: '90px'}, ]; class DashboardPage extends React.Component { diff --git a/src/subsets/ui/dashboard/subset-stepper/steps.ts b/src/subsets/ui/dashboard/subset-stepper/steps.ts index b2540c78..cd3111c0 100644 --- a/src/subsets/ui/dashboard/subset-stepper/steps.ts +++ b/src/subsets/ui/dashboard/subset-stepper/steps.ts @@ -6,28 +6,28 @@ import BasicInfoStep from 'subsets/ui/dashboard/subset-stepper/steps/basic-info' const steps = [ { id: 1, - name: 'Basic information', + name: 'subsets.dashboard.p.stepper.basicInfo.stepName', path: 'edit', component: BasicInfoStep, exact: true, }, { id: 2, - name: 'List of accessions', + name: 'subsets.dashboard.p.stepper.accessionList.stepName', path: 'edit/list-of-accessions', component: AccessionsListStep, exact: true, }, { id: 3, - name: 'Subset creators', + name: 'subsets.dashboard.p.stepper.creators.stepName', path: 'edit/creators', component: CreatorsStep, exact: true, }, { id: 4, - name: 'Review and publish', + name: 'subsets.dashboard.p.stepper.review.stepName', path: 'edit/review-and-publish', component: ReviewStep, exact: true, diff --git a/src/subsets/ui/dashboard/subset-stepper/steps/accessions-list/ListOfAccessions.tsx b/src/subsets/ui/dashboard/subset-stepper/steps/accessions-list/ListOfAccessions.tsx index 86579f60..2bdce623 100644 --- a/src/subsets/ui/dashboard/subset-stepper/steps/accessions-list/ListOfAccessions.tsx +++ b/src/subsets/ui/dashboard/subset-stepper/steps/accessions-list/ListOfAccessions.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import { translate } from 'react-i18next'; import {withStyles} from '@material-ui/core/styles'; import Input from '@material-ui/core/Input'; import InputLabel from '@material-ui/core/InputLabel'; @@ -25,6 +26,7 @@ interface IListOfAccession extends React.ClassAttributes { listAccessions: (filter: string | AccessionFilter, page: IPageRequest) => Promise>; subset: Subset; onAccessionsUpdated: (AccessionRefs: AccessionRef[]) => void; + t: any; } const styleSheet = { @@ -72,17 +74,18 @@ class ListOfAccession extends React.Component { public render() { - const {classes, subset} = this.props; + const {classes, subset, t} = this.props; + const { subsetAccessions } = this.state; return (
-

INSTRUCTIONS FOR USE

+

{ t('subsets.dashboard.p.stepper.accessionList.instructions') }

    -
  • Use "Acccessions" sheet from template: Subset template.
  • -
  • Do not change header name in the template
  • -
  • Fill the template with the information of the accessions, save it.
  • -
  • Copy and paste the table from Excel into the text field below.
  • +
  • { t('subsets.dashboard.p.stepper.accessionList.detailedInstructions1') }{ t('subsets.dashboard.p.stepper.accessionList.Subset template') }.
  • +
  • { t('subsets.dashboard.p.stepper.accessionList.detailedInstructions2') }
  • +
  • { t('subsets.dashboard.p.stepper.accessionList.detailedInstructions3') }
  • +
  • { t('subsets.dashboard.p.stepper.accessionList.detailedInstructions4') }
@@ -91,23 +94,23 @@ class ListOfAccession extends React.Component {
- List of accessions described in the dataset - + { t('subsets.dashboard.p.stepper.accessionList.listOfAccessions') } +
-

Accession list: { subset.accessionRefs ? subset.accessionRefs.length : 0 } rows

- { subset.accessionRefs && - ( - { - doi: accessionRef.accession.doi, - instCode: accessionRef.accession.institute.code, - acceNumb: accessionRef.accession.accessionNumber, - genus: accessionRef.accession.taxonomy.genus, - } - )) }/> +

{ t('subsets.dashboard.p.stepper.accessionList.accessionListCount', {count: subsetAccessions && subsetAccessions.length || 0}) }

+ { subsetAccessions && + ( + { + doi: accessionRef.accession.doi, + instCode: accessionRef.accession.institute.code, + acceNumb: accessionRef.accession.accessionNumber, + genus: accessionRef.accession.taxonomy.genus, + } + )) }/> }
); @@ -138,4 +141,4 @@ class ListOfAccession extends React.Component { } } -export default withStyles(styleSheet)(ListOfAccession); +export default translate()(withStyles(styleSheet)(ListOfAccession)); diff --git a/src/subsets/ui/dashboard/subset-stepper/steps/basic-info/BasicInfoForm.tsx b/src/subsets/ui/dashboard/subset-stepper/steps/basic-info/BasicInfoForm.tsx index b9f36d17..6cd92bc5 100644 --- a/src/subsets/ui/dashboard/subset-stepper/steps/basic-info/BasicInfoForm.tsx +++ b/src/subsets/ui/dashboard/subset-stepper/steps/basic-info/BasicInfoForm.tsx @@ -14,13 +14,14 @@ interface ILoginContainerProps extends React.ClassAttributes { initialValues: any; classes: any; uuid: string; + t: any; } class BasicInfoStep extends React.Component { public render() { - const {handleSubmit} = this.props; + const {handleSubmit, t} = this.props; return (
@@ -28,7 +29,7 @@ class BasicInfoStep extends React.Component { required name="title" component={ TextField } - label="Subset title" + label={ t('subsets.dashboard.p.stepper.basicInfo.subsetTitle') } placeholder="some title" validate={ [Validators.required] } /> @@ -36,32 +37,32 @@ class BasicInfoStep extends React.Component { required name="wiewsCode" component={ TextField } - label="Institute code" + label={ t('subsets.dashboard.p.stepper.basicInfo.instituteCode') } placeholder="NGA039" validate={ [Validators.required] } /> diff --git a/src/subsets/ui/dashboard/subset-stepper/steps/basic-info/index.tsx b/src/subsets/ui/dashboard/subset-stepper/steps/basic-info/index.tsx index 3bf7be9c..5a335788 100644 --- a/src/subsets/ui/dashboard/subset-stepper/steps/basic-info/index.tsx +++ b/src/subsets/ui/dashboard/subset-stepper/steps/basic-info/index.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import { translate } from 'react-i18next'; import {bindActionCreators} from 'redux'; import {isInvalid, submit} from 'redux-form'; import {connect} from 'react-redux'; @@ -11,11 +12,12 @@ import StepperTemplate from 'ui/common/stepper/StepperTemplate'; interface ISubsetProps extends React.ClassAttributes { isInvalidForm: boolean; submit: any; + t: any; } class BasicInfoStep extends StepperTemplate { - protected renderContent = () => (); + protected renderContent = () => (); protected gotoStep = (id) => { const {onGotoStep, submit} = this.props; @@ -41,4 +43,4 @@ const mapDispatchToProps = (dispatch) => bindActionCreators({ export default connect( mapStateToProps, mapDispatchToProps, -)(BasicInfoStep); +)(translate()(BasicInfoStep)); diff --git a/src/subsets/ui/dashboard/subset-stepper/steps/creators/SubsetCreatorForm.tsx b/src/subsets/ui/dashboard/subset-stepper/steps/creators/SubsetCreatorForm.tsx index 88d53e15..df02109f 100644 --- a/src/subsets/ui/dashboard/subset-stepper/steps/creators/SubsetCreatorForm.tsx +++ b/src/subsets/ui/dashboard/subset-stepper/steps/creators/SubsetCreatorForm.tsx @@ -53,7 +53,7 @@ const renderRadioGroup = translate()(({input, meta, t, classes}) => { return ( - Role: + { t(`subsets.dashboard.p.stepper.creators.Role`) } { className={ classes.RadioGrid } > { Object.keys(CreatorRole).map((role) => ( - } /> + } /> )) } @@ -79,7 +79,7 @@ class SubsetCreatorForm extends React.Component { this.props.deleteCreatorRequest(fields.get(index)); } - public renderCreators = ({ classes, fields, meta: { touched, error, submitFailed } }) => { + public renderCreators = ({ classes, fields, meta: { touched, error, submitFailed } , t}) => { return(
@@ -93,8 +93,8 @@ class SubsetCreatorForm extends React.Component {
{
), @@ -141,14 +141,15 @@ class SubsetCreatorForm extends React.Component { } public render() { + const { t } = this.props; return (
- +
@@ -156,7 +157,7 @@ class SubsetCreatorForm extends React.Component { } } -export default reduxForm({ +export default translate()(reduxForm({ form: SUBSET_CREATOR_FORM, enableReinitialize: true, -})(translate()(((withStyles as any)(styles)(SubsetCreatorForm)))); +})(translate()(((withStyles as any)(styles)(SubsetCreatorForm))))); diff --git a/src/translations.json b/src/translations.json new file mode 100644 index 00000000..8e45fe94 --- /dev/null +++ b/src/translations.json @@ -0,0 +1,168 @@ +{ + "public": { + "p": { + "welcome": { + "About Genesys PGR": "About the Genesys PGR", + "Bookmark this page": "Bookmark this page", + "Contribute to Genesys": "Contribute to Genesys", + "Subscribe to Newsletter": "Subscribe to Newsletter", + "search": { + "placeholder": "Search Genesys...", + "suggestion0": "Try 'maize' or 'wild triticum'", + "suggestion1": "How about 'rice'", + "suggestion2": "What is 'MARDI' up to?", + "suggestion3": "'IRGC 1000' maybe", + "suggestion4": "Try 'leaf shape'", + "suggestion5": "Anything on 'cassava'?", + "suggestion6": "Maybe 'drought'" + } + } + }, + "search": { + "group": { + "descriptor": "Descriptors", + "accession": "Accessions", + "crop": "Crops", + "partner": "Data providers", + "dataset": "Datasets" + } + }, + "prettyF": { + "NOT": "Excluding {{what}}", + "accessions": { + "crop": "Crop", + "acceNumb": "Accession number", + "seqNo": "Sequential number", + "sampStat": "Biological status", + "storage": "Storage", + "geo": { + "latitude": "Latitude", + "longitude": "Longitude", + "elevation": "Elevation" + }, + "holder": { + "code": "Holder", + "country": { + "iso3": "Holder country", + "region": "Holder region" + } + }, + "lastModifiedDate": { + "": "Last updated", + "ge": "Updated after", + "le": "Updated before" + }, + "taxa": { + "genus": "Genus", + "species": "Species", + "subtaxa": "Subtaxa" + }, + "origin": { + "iso3": "Origin" + }, + "taxonomy": { + "genus": "Genus", + "species": "Species", + "subtaxa": "Subtaxon" + }, + "sgsv": "Svalbard", + "mlsStatus": "MLS", + "available": "Available", + "historic": "Historic" + }, + "subsets": { + "title": "Title", + "crop": "Crop", + "institutes": "Institute code", + "description": "Description" + }, + "wiews": { + "code": "Institute code", + "accessions": "Accessions in Genesys", + "country": { + "iso3": "Country code" + } + }, + "users": { + "role": "Role", + "enabled": "Active", + "expired": "Exptired", + "locked": "Locked", + "email": "E-mail address", + "uuid": "UUID" + } + } + }, + "dashboard": { + "p": { + "dashboard": { + "title": "My Dashboard", + "subtitle": "Manage data published on Genesys" + } + } + }, + "common": { + "Genesys PGR": "Genesys PGR", + "Not found": "Not found", + "Nothing matches your request": "Nothing matches your request", + "label": { + "metadata": "Record metadata" + }, + "footer": { + "About Genesys": "About Genesys", + "Contact Us": "Contact us", + "Copyright policy": "Copyright policy", + "Disclaimer": "Disclaimer", + "Privacy policy": "Privacy policy", + "Report an issue": "Report an issue", + "Source code": "Source code", + "Terms and Conditions of Use": "Terms and Conditions of Use", + "Translate Genesys": "Translate Genesys", + "copyright": "© {{from}} - {{to}} Data providers and the Crop Trust" + }, + "menu": { + "Controlled vocabularies": "Controlled vocabularies", + "Datasets": "Datasets", + "Descriptor lists": "Crop descriptors", + "Descriptors": "Descriptors", + "Home": "Home", + "My Dashboard": "My dashboard", + "My profile": "My profile", + "Partners": "Partners", + "Admin": "Administration", + "login": "Login", + "register": "Registration" + } + }, + "datasets": { + "common": { + "modelName": "Dataset", + "modelName_plural": "Datasets", + "stats": "C&E Dataset", + "stats_plural": "C&E Datasets", + "creator": { + "role": { + "MANAGER": "Data manager", + "COLLECTOR": "Data collector", + "DIGITIZER": "Data digitizer", + "CURATOR": "Data curator" + }, + "roledesc": { + "MANAGER": "Responsible of the planning and execution of the germplasm characterization and evaluation activity which resulted in the dataset. Oversees the collection and management of characterization and evaluation data, and has final sign-off on publication.", + "COLLECTOR": "Records germplasm characterization or evaluation data in the field.", + "DIGITIZER": "Digitizes data.", + "CURATOR": "Organizes and validates data and metadata in correct format, ensures quality of both." + } + } + } + }, + "geo": { + "common": { + "location": "Location", + "latitude": "Latitude", + "longitude": "Longitude", + "address": "Address", + "country": "Country" + } + } +} \ No newline at end of file diff --git a/src/ui/catalog/accession/AccessionRefsTable.tsx b/src/ui/catalog/accession/AccessionRefsTable.tsx index a5c9dacd..cb8d7d04 100644 --- a/src/ui/catalog/accession/AccessionRefsTable.tsx +++ b/src/ui/catalog/accession/AccessionRefsTable.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import { withStyles } from '@material-ui/core/styles'; import { AccessionRef } from 'model/accession/AccessionRef'; @@ -34,6 +35,7 @@ const styles = (theme) => ({ interface IAccessionRefsTableProps extends React.ClassAttributes { classes: any; AccessionRefs: AccessionRef[]; + t: any; } class AccessionRefsTable extends React.Component { @@ -43,7 +45,7 @@ class AccessionRefsTable extends React.Component } public render() { - const { AccessionRefs, classes } = this.props; + const { AccessionRefs, classes, t } = this.props; const rowGetter = ({ index }) => AccessionRefs[index]; const renderDoi = ({ cellData }) => ; const rowClassName = ({ index }) => index === -1 ? '' : `${classes.tableCell} ${index % 2 === 0 ? classes.evenRow : classes.oddRow}`; @@ -62,11 +64,11 @@ class AccessionRefsTable extends React.Component rowClassName={ rowClassName } headerClassName={ `back-green` } > - - - - - + + + + + ) } @@ -74,4 +76,4 @@ class AccessionRefsTable extends React.Component } } -export default withStyles(styles)(AccessionRefsTable); +export default translate()(withStyles(styles)(AccessionRefsTable)); diff --git a/src/ui/common/ItemsEditor.tsx b/src/ui/common/ItemsEditor.tsx index 4d87924d..6ca711c3 100644 --- a/src/ui/common/ItemsEditor.tsx +++ b/src/ui/common/ItemsEditor.tsx @@ -1,10 +1,11 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import { FieldArray } from 'redux-form'; import Button from '@material-ui/core/Button'; import Grid from '@material-ui/core/Grid'; import {log} from 'utilities/debug'; -const renderMembers = ({ fields, itemLabel, itemEditor, addItem, removeItem }) => { +const renderMembers = ({ fields, itemLabel, itemEditor, addItem, removeItem, t }) => { const onAddMember = (e) => { const item = addItem(); @@ -23,7 +24,7 @@ const renderMembers = ({ fields, itemLabel, itemEditor, addItem, removeItem }) = } if (fields.length > 100) { - return
Don't use the ItemsEditor for more than 100 items!
; + return
{ t('common:label.itemEditorWarn') }
; } return ( @@ -35,24 +36,24 @@ const renderMembers = ({ fields, itemLabel, itemEditor, addItem, removeItem }) = { itemEditor(member, index, fields, itemLabel) } - +
)) } - +
); }; -const ItemsEditor = ({ name, itemLabel, addItem, removeItem, component }) => { +const ItemsEditor = ({ name, itemLabel, addItem, removeItem, component, t }) => { return ( - + ); }; -export default ItemsEditor; +export default translate()(ItemsEditor); diff --git a/src/ui/common/Menu.tsx b/src/ui/common/Menu.tsx index 4e0d6a01..ee8e0a66 100644 --- a/src/ui/common/Menu.tsx +++ b/src/ui/common/Menu.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import { withStyles } from '@material-ui/core/styles'; import { Link } from 'react-router-dom'; @@ -44,18 +45,19 @@ interface IMenuItemProps extends React.ClassAttributes { label: any; icon?: any; to: string; + t: any; } class MenuItem extends React.Component { public render() { - const {to, label, children, classes, icon} = this.props; + const {to, label, children, classes, icon, t} = this.props; return(
{ icon && { icon } } - { label } + { typeof label === 'string' ? t(label) : label }
@@ -66,4 +68,4 @@ class MenuItem extends React.Component { } } -export default withStyles(style)(MenuItem); +export default translate()(withStyles(style)(MenuItem)); diff --git a/src/ui/common/Properties.tsx b/src/ui/common/Properties.tsx index 7c5c4840..1b5025eb 100644 --- a/src/ui/common/Properties.tsx +++ b/src/ui/common/Properties.tsx @@ -1,5 +1,6 @@ import * as React from 'react'; import { withStyles, WithStyles } from '@material-ui/core/styles'; +import { translate } from 'react-i18next'; import Grid from '@material-ui/core/Grid'; @@ -51,20 +52,21 @@ interface IItemProps extends React.ClassAttributes { small?: boolean; keepEmpty?: boolean; numeric?: boolean; + t: any; // children: any; } class PropertiesItem1 extends React.Component, any> { public render() { - const { keepEmpty, small, numeric, title, classes, children } = this.props; + const { keepEmpty, small, numeric, title, classes, children, t } = this.props; if (!keepEmpty && ! children) { return null; } return ( - { title } + { typeof title === 'string' ? t(title) : title } { children } @@ -91,6 +93,6 @@ class Properties1 extends React.Component { return ( - + { topSection } diff --git a/src/ui/common/Tabs.tsx b/src/ui/common/Tabs.tsx index 6078dfaa..d6a7d289 100644 --- a/src/ui/common/Tabs.tsx +++ b/src/ui/common/Tabs.tsx @@ -4,6 +4,7 @@ // Navigation is peformed using router // import * as React from 'react'; +import {translate} from 'react-i18next'; import {connect} from 'react-redux'; import { Link } from 'react-router-dom'; import {bindActionCreators} from 'redux'; @@ -75,7 +76,7 @@ class Tab extends React.Component { class Tabs extends React.Component { public render() { - const { tab, children, navigateTo, actions, classes } = this.props; + const { tab, children, navigateTo, actions, classes, t } = this.props; const tabs = (children as Tab[]).map((ch) => { return { @@ -97,7 +98,7 @@ class Tabs extends React.Component { - { tabs.map((tab) => ) } + { tabs.map((tab) => ) } @@ -117,6 +118,6 @@ const mapDispatchToProps = (dispatch) => bindActionCreators({ navigateTo, }, dispatch); -const tabs = connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(Tabs)); +const tabs = translate()(connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(Tabs))); export { tabs as default, Tab }; diff --git a/src/ui/common/buttons/ActionButton.tsx b/src/ui/common/buttons/ActionButton.tsx index 42c961dd..2781dc42 100644 --- a/src/ui/common/buttons/ActionButton.tsx +++ b/src/ui/common/buttons/ActionButton.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import { translate } from 'react-i18next'; import Button from '@material-ui/core/Button'; interface IActionButtonProps extends React.ClassAttributes { @@ -6,18 +7,19 @@ interface IActionButtonProps extends React.ClassAttributes { title: string; action: any; style?: any; + t: any; } class ActionButton extends React.Component { public render() { - const { title, action, variant = 'raised', style } = this.props; + const { title, action, variant = 'raised', style, t } = this.props; return ( ); } } -export default ActionButton; +export default translate()(ActionButton); diff --git a/src/ui/common/buttons/BackButton.tsx b/src/ui/common/buttons/BackButton.tsx index 87ff1eb7..965b8098 100644 --- a/src/ui/common/buttons/BackButton.tsx +++ b/src/ui/common/buttons/BackButton.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import Button from '@material-ui/core/Button'; @@ -13,6 +14,7 @@ interface IBackButtonProps extends React.ClassAttributes { preferDefaultTarget?: boolean; navigateTo: (path: string) => void; style?: any; + t: any; } class BackButton extends React.Component { @@ -35,10 +37,10 @@ class BackButton extends React.Component { } public render() { - const { defaultBackText, style } = this.props; + const { defaultBackText, style, t } = this.props; return ( ); } @@ -53,4 +55,4 @@ const mapDispatchToProps = (dispatch) => bindActionCreators({ navigateTo, }, dispatch); -export default connect(mapStateToProps, mapDispatchToProps)(BackButton); +export default translate()(connect(mapStateToProps, mapDispatchToProps)(BackButton)); diff --git a/src/ui/common/buttons/UploadButton.tsx b/src/ui/common/buttons/UploadButton.tsx index 111b0749..36fdcdf3 100644 --- a/src/ui/common/buttons/UploadButton.tsx +++ b/src/ui/common/buttons/UploadButton.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import Button from '@material-ui/core/Button'; interface IUploadButtonProps extends React.ClassAttributes { @@ -7,6 +8,7 @@ interface IUploadButtonProps extends React.ClassAttributes { title?: string; multiple?: boolean; style?: any; + t: any; } class UploadButton extends React.Component { @@ -19,7 +21,7 @@ class UploadButton extends React.Component { } public render() { - const { title = 'Choose file', variant = 'raised', style, multiple = false } = this.props; + const { title = 'common:action.chooseFile', variant = 'raised', style, multiple = false, t } = this.props; return (
{ onChange={ this.upload } />
); } } -export default UploadButton; +export default translate()(UploadButton); diff --git a/src/ui/common/checkbox/index.tsx b/src/ui/common/checkbox/index.tsx index a5653f3f..7b7f270b 100644 --- a/src/ui/common/checkbox/index.tsx +++ b/src/ui/common/checkbox/index.tsx @@ -1,8 +1,9 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import FormControlLabel from '@material-ui/core/FormControlLabel'; import Checkbox from '@material-ui/core/Checkbox'; -const ReduxCheckbox = ({input: {value, onChange}, label = null, style = {height: '40px'}, ...rest}) => ( +const ReduxCheckbox = ({input: {value, onChange}, label = null, style = {height: '40px'}, t, ...rest}) => ( } - label={ label } + label={ t(label) } { ...rest } /> ); -export default ReduxCheckbox; +export default translate()(ReduxCheckbox); diff --git a/src/ui/common/csv-configuration/CSVConfiguration.tsx b/src/ui/common/csv-configuration/CSVConfiguration.tsx index 91998896..84505319 100644 --- a/src/ui/common/csv-configuration/CSVConfiguration.tsx +++ b/src/ui/common/csv-configuration/CSVConfiguration.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import { ICsvConfiguration } from 'utilities/CSV'; @@ -23,6 +24,7 @@ class CSVConfig implements ICsvConfiguration { interface ICSVConfigurationProps extends React.ClassAttributes { config: CSVConfig; onChange: (value: CSVConfig) => void; + t: any; } class CSVConfiguration extends React.Component { @@ -88,15 +90,16 @@ class CSVConfiguration extends React.Component { } public render() { + const {t} = this.props; return (
- + - Auto-detect + { t('common:csv.autoDetect') } } @@ -105,53 +108,53 @@ class CSVConfiguration extends React.Component { - Separator character + { t('common:csv.separator') } } /> } /> } /> } /> } /> } + control={ } /> - Escape character - + { t('common:csv.escapeCharacter') } + - Quote character - + { t('common:csv.quoteCharacter') } + @@ -161,4 +164,5 @@ class CSVConfiguration extends React.Component { } } -export { CSVConfiguration as default, CSVConfig }; +const translatedCSV = translate()(CSVConfiguration); +export { translatedCSV as default, CSVConfig }; diff --git a/src/ui/common/file-uploader/TargetBox.tsx b/src/ui/common/file-uploader/TargetBox.tsx index 8ab24212..f407008f 100644 --- a/src/ui/common/file-uploader/TargetBox.tsx +++ b/src/ui/common/file-uploader/TargetBox.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import {ConnectDropTarget, DropTarget, DropTargetConnector, DropTargetMonitor} from 'react-dnd'; import {withStyles} from '@material-ui/core/styles'; import UploadButton from 'ui/common/buttons/UploadButton'; @@ -22,6 +23,7 @@ export interface ITargetBoxProps extends React.ClassAttributes { onDrop: (props: ITargetBoxProps, monitor: DropTargetMonitor) => void; classes: any; handleUploading: (files: File[]) => void; + t: any; } const boxTarget = { @@ -39,21 +41,21 @@ class TargetBox extends React.Component { } public render() { - const { canDrop, isOver, connectDropTarget, classes, handleUploading } = this.props; + const { canDrop, isOver, connectDropTarget, classes, handleUploading, t } = this.props; const isActive = canDrop && isOver; return ( connectDropTarget && connectDropTarget(
- { isActive ? 'Release to upload' + { isActive ? t('common:fileUploader.release') :
- Drag files here
or + { t('common:fileUploader.dragFiles') }
@@ -70,4 +72,4 @@ const dropTargetWrap = DropTarget((props: ITargetBoxProps) => props.accepts, box canDrop: monitor.canDrop(), })); -export default (withStyles as any)(styles)(dropTargetWrap(TargetBox)); +export default translate()((withStyles as any)(styles)(dropTargetWrap(TargetBox))); diff --git a/src/ui/common/filter/BooleanFilter.tsx b/src/ui/common/filter/BooleanFilter.tsx index 7af38a75..0ea2db0e 100644 --- a/src/ui/common/filter/BooleanFilter.tsx +++ b/src/ui/common/filter/BooleanFilter.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import { Field } from 'redux-form'; import Radio from '@material-ui/core/Radio'; @@ -10,6 +11,7 @@ import FormControl from '@material-ui/core/FormControl'; interface IBooleanFilterInternal extends React.ClassAttributes { input: any; label: string; + t: any; } class BooleanFilterInternal extends React.Component { @@ -33,7 +35,7 @@ class BooleanFilterInternal extends React.Component } public render() { - const { label } = this.props; + const { label, t } = this.props; return (
@@ -42,9 +44,9 @@ class BooleanFilterInternal extends React.Component value={ `${this.state.value}` } onChange={ this.handleChange } > - } label="Yes" /> - } label="No" /> - } label="Either" /> + } label={ t('common:label.yes') } /> + } label={ t('common:label.no') } /> + } label={ t('common:label.either') } />
@@ -55,22 +57,24 @@ class BooleanFilterInternal extends React.Component interface IBooleanFilter extends React.ClassAttributes { name: string; label?: string; + t: any; } class BooleanFilter extends React.Component { public render() { - const { name , label } = this.props; + const { name , label, t } = this.props; return (
); } } -export default BooleanFilter; +export default translate()(BooleanFilter); diff --git a/src/ui/common/filter/CollapsibleComponentSearch.tsx b/src/ui/common/filter/CollapsibleComponentSearch.tsx index 630c89c9..142fc72e 100644 --- a/src/ui/common/filter/CollapsibleComponentSearch.tsx +++ b/src/ui/common/filter/CollapsibleComponentSearch.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import PlayArrow from '@material-ui/icons/PlayArrow'; import {withStyles} from '@material-ui/core/styles'; import Collapse from '@material-ui/core/Collapse'; @@ -8,6 +9,7 @@ interface ICollapsibleComponentSearch extends React.ClassAttributes { classes: any; title: string; collapsed?: boolean; + t: any; } const styles = (theme) => ({ @@ -40,12 +42,12 @@ class CollapsibleComponentSearch extends React.Component
- { title } + { t(title) }
{ input: any; placeholder: string; label: string; + t: any; } class DateFilterInternal extends React.Component { @@ -74,12 +76,12 @@ class DateFilterInternal extends React.Component { } public render() { - const {label} = this.props; + const {label, t} = this.props; return (
{ /> { interface IDateFilter extends React.ClassAttributes { name: string; label: string; + t: any; } // NumberFilter supports eq, ge, gt, le, lt @@ -111,17 +114,18 @@ class DateFilter extends React.Component { } public render() { - const { name, label } = this.props; + const { name, label, t } = this.props; return (
); } } -export default DateFilter; +export default translate()(DateFilter); diff --git a/src/ui/common/filter/ExpandFiltersComponent.tsx b/src/ui/common/filter/ExpandFiltersComponent.tsx index 840da5ec..1b9e8986 100644 --- a/src/ui/common/filter/ExpandFiltersComponent.tsx +++ b/src/ui/common/filter/ExpandFiltersComponent.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import {withStyles} from '@material-ui/core/styles'; import compose from 'recompose/compose'; import withWidth from '@material-ui/core/withWidth'; @@ -8,6 +9,7 @@ interface IExpandFiltersComponentProps extends React.ClassAttributes { classes: any; width: any; title: string; + t: any; } const styles = (theme) => ({ @@ -17,12 +19,12 @@ const styles = (theme) => ({ class ExpandFiltersComponent extends React.Component { public render() { - const { classes, title, children} = this.props; + const { classes, title, children, t} = this.props; return (

- { title } + { t(title) }

@@ -32,4 +34,4 @@ class ExpandFiltersComponent extends React.Component ({ // // Renders a standard filters block -const FiltersBlock = ({ title, children, handleSubmit, onSubmit, initialize, classes, showSnackbar }) => { +const FiltersBlock = ({ title, children, handleSubmit, onSubmit, initialize, classes, showSnackbar, t }) => { const scrollToTop = () => { if (window) { window.scrollTo(0, 0); @@ -58,8 +59,8 @@ const FiltersBlock = ({ title, children, handleSubmit, onSubmit, initialize, cla
{ children }
- - + +
@@ -71,4 +72,4 @@ const mapDispatchToProps = (dispatch) => bindActionCreators({ showSnackbar, }, dispatch); -export default connect(null, mapDispatchToProps)(withStyles(styles)(FiltersBlock)); +export default translate()(connect(null, mapDispatchToProps)(withStyles(styles)(FiltersBlock))); diff --git a/src/ui/common/filter/NumberFilter.tsx b/src/ui/common/filter/NumberFilter.tsx index da8785a2..f40843ca 100644 --- a/src/ui/common/filter/NumberFilter.tsx +++ b/src/ui/common/filter/NumberFilter.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import { Field } from 'redux-form'; import TextField from '@material-ui/core/TextField'; @@ -10,6 +11,7 @@ interface INumberFilterInternal extends React.ClassAttributes { input: any; placeholder: string; label: string; + t: any; } class NumberFilterInternal extends React.Component { @@ -58,21 +60,21 @@ class NumberFilterInternal extends React.Component { } public render() { - const { label } = this.props; + const { label, t } = this.props; return (
@@ -83,6 +85,7 @@ class NumberFilterInternal extends React.Component { interface INumberFilter extends React.ClassAttributes { name: string; label: string; + t: any; } // NumberFilter supports eq, ge, gt, le, lt @@ -93,17 +96,18 @@ class NumberFilter extends React.Component { } public render() { - const { name, label } = this.props; + const { name, label, t } = this.props; return (
); } } -export default NumberFilter; +export default translate()(NumberFilter); diff --git a/src/ui/common/filter/PrettyFilters.tsx b/src/ui/common/filter/PrettyFilters.tsx index 60e03d91..e0c85d5c 100644 --- a/src/ui/common/filter/PrettyFilters.tsx +++ b/src/ui/common/filter/PrettyFilters.tsx @@ -110,15 +110,15 @@ function getLabelName(path, value, lookups, prefix, t) { if (typeof name === 'boolean') { if (name) { - return t(`f.${prefix}.${prettyPath}`); + return t(`public.prettyF.${prefix}.${prettyPath}`); } - return t('f.NOT', { what: t(`f.${prefix}.${prettyPath.replace(/^NOT\./, '')}`) }); + return t('public.prettyF.NOT', { what: t(`public.prettyF.${prefix}.${prettyPath.replace(/^NOT\./, '')}`) }); } const translatedPrettyPath = prettyPath.startsWith('NOT') ? - t('f.NOT', { what: t(`f.${prefix}.${prettyPath.replace(/^NOT\./, '')}`) }) + t('public.prettyF.NOT', { what: t(`public.prettyF.${prefix}.${prettyPath.replace(/^NOT\./, '')}`) }) : - t(`f.${prefix}.${prettyPath}`); + t(`public.prettyF.${prefix}.${prettyPath}`); const translatedPrettyName = t(`${name}`); diff --git a/src/ui/common/filter/StringArrFilter.tsx b/src/ui/common/filter/StringArrFilter.tsx index abde408f..2e6add83 100644 --- a/src/ui/common/filter/StringArrFilter.tsx +++ b/src/ui/common/filter/StringArrFilter.tsx @@ -309,7 +309,7 @@ class StringArrFilter extends React.Component { { searchType: any; placeholder: string; label: string; + t: any; } // searchType can be: "contains", "eq"- equals, "sw" - start with @@ -79,19 +81,19 @@ class StringFilter extends React.Component { } public render() { - const { name , searchType, label, placeholder} = this.props; + const { name , searchType, label, placeholder, t} = this.props; return (
); } } -export default StringFilter; +export default translate()(StringFilter); diff --git a/src/ui/common/filter/TextFilter.tsx b/src/ui/common/filter/TextFilter.tsx index 20819612..52f6abf7 100644 --- a/src/ui/common/filter/TextFilter.tsx +++ b/src/ui/common/filter/TextFilter.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import { Field } from 'redux-form'; import TextField from '@material-ui/core/TextField'; @@ -7,6 +8,7 @@ interface ITextFilterInternal extends React.ClassAttributes { input: any; label: string; placeholder?: string; + t: any; } class TextFilterInternal extends React.Component { @@ -35,14 +37,14 @@ class TextFilterInternal extends React.Component { } public render() { - const { label, placeholder } = this.props; + const { label, placeholder, t } = this.props; return (
@@ -55,18 +57,20 @@ interface ITextFilter extends React.ClassAttributes { label: string; placeholder?: string; className?: string; + t: any; } class TextFilter extends React.Component { public render() { - const { name , label, className, ...other } = this.props; + const { name , label, className, t, ...other } = this.props; return (
@@ -74,4 +78,4 @@ class TextFilter extends React.Component { } } -export default TextFilter; +export default translate()(TextFilter); diff --git a/src/ui/common/forms/FormControl.tsx b/src/ui/common/forms/FormControl.tsx index 2cc904e9..32ae2fa5 100644 --- a/src/ui/common/forms/FormControl.tsx +++ b/src/ui/common/forms/FormControl.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import { withStyles } from '@material-ui/core/styles'; import InputLabel from '@material-ui/core/InputLabel'; @@ -12,6 +13,7 @@ interface IProps { children: any; meta?: any; disableAnimation?: boolean; + t: any; } const styles = (theme) => { @@ -24,13 +26,13 @@ const styles = (theme) => { }); }; -const FormControl = ({ fullWidth = false, required = false, label = null, children, meta = {}, disableAnimation = false, classes }: IProps) => { +const FormControl = ({ fullWidth = false, required = false, label = null, children, meta = {}, disableAnimation = false, classes, t }: IProps) => { // console.log('Meta', meta); const { error, warning } = meta; return ( - { label && { label } } + { label && { t(label) } } { children } { ((error &&
{ error }
) @@ -41,4 +43,4 @@ const FormControl = ({ fullWidth = false, required = false, label = null, childr ); }; -export default withStyles(styles)(FormControl); +export default translate()(withStyles(styles)(FormControl)); diff --git a/src/ui/common/forms/Toggle.tsx b/src/ui/common/forms/Toggle.tsx index 7853ab29..fb0e9bfb 100644 --- a/src/ui/common/forms/Toggle.tsx +++ b/src/ui/common/forms/Toggle.tsx @@ -1,11 +1,12 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import FormControlLabel from '@material-ui/core/FormControlLabel'; import Switch from '@material-ui/core/Switch'; // // Render a switch form control (a yes/no toggler) -const renderToggler = ({input, falseIsNull = false, label, meta, ...rest}: { falseIsNull?: boolean } & any) => { +const renderToggler = ({input, falseIsNull = false, label, meta, t, ...rest}: { falseIsNull?: boolean } & any) => { const onChange = (event, checked) => { input.onChange(checked ? checked : (falseIsNull && ! checked ? null : checked)); @@ -14,9 +15,9 @@ const renderToggler = ({input, falseIsNull = false, label, meta, ...rest}: { fal return ( } - label={ label } + label={ t(label) } /> ); }; -export default renderToggler; +export default translate()(renderToggler); diff --git a/src/ui/common/heading/ContentHeader.tsx b/src/ui/common/heading/ContentHeader.tsx index 9112f51f..1bceaa22 100644 --- a/src/ui/common/heading/ContentHeader.tsx +++ b/src/ui/common/heading/ContentHeader.tsx @@ -3,35 +3,44 @@ import Grid from '@material-ui/core/Grid'; import Hidden from '@material-ui/core/Hidden'; import { connect } from 'react-redux'; import { setPageTitle } from 'actions/pageTitle'; +import { translate } from 'react-i18next'; import { bindActionCreators } from 'redux'; interface IContentHeader extends React.ClassAttributes { title: string; subTitle?: string; setPageTitle: (title: string) => void; + t: any; } class ContentHeader extends React.Component { public constructor(props: any) { super(props); - const {title, setPageTitle} = this.props; - setPageTitle(title); + const {title, setPageTitle, t} = this.props; + setPageTitle(t(title)); + } + + public componentWillReceiveProps(nextProps) { + const {title, setPageTitle, t} = this.props; + if (t && title) { + setPageTitle(t(title)); + } } public render() { - const { title, subTitle} = this.props; + const { title, subTitle, t} = this.props; return (

- { title } + { t(title) }

- { subTitle } + { t(subTitle) }

@@ -44,5 +53,5 @@ const mapDispatchToProps = (dispatch) => bindActionCreators({ setPageTitle, }, dispatch); -export default connect(null, mapDispatchToProps)(ContentHeader); +export default connect(null, mapDispatchToProps)(translate()(ContentHeader)); diff --git a/src/ui/common/heading/ContentHeaderWithButton.tsx b/src/ui/common/heading/ContentHeaderWithButton.tsx index abb1ff34..3e3cdb48 100644 --- a/src/ui/common/heading/ContentHeaderWithButton.tsx +++ b/src/ui/common/heading/ContentHeaderWithButton.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import {withStyles} from '@material-ui/core/styles'; import Grid from '@material-ui/core/Grid'; @@ -52,6 +53,7 @@ interface IContentHeaderWithButtonProps extends React.ClassAttributes { classes: any; title: string; buttons: any; + t: any; } class ContentHeaderWithButton extends React.Component { @@ -61,13 +63,13 @@ class ContentHeaderWithButton extends React.Component

- { title } + { typeof title === 'string' ? t(title) : title }

@@ -78,4 +80,4 @@ class ContentHeaderWithButton extends React.Component ( +const Section = ({ className, children, title, t }: { title: string } & any) => (
-

{ title }

+

{ t(title) }

@@ -15,4 +16,4 @@ const Section = ({ className, children, title }: { title: string } & any) => ( ); -export default Section; +export default translate()(Section); diff --git a/src/ui/common/not-found/index.tsx b/src/ui/common/not-found/index.tsx index a3838087..06ce4b18 100644 --- a/src/ui/common/not-found/index.tsx +++ b/src/ui/common/not-found/index.tsx @@ -13,8 +13,8 @@ class NotFound extends React.Component { } return (
-

{ t('Not found') }

-

{ t('Nothing matches your request') }

+

{ t('common.Not found') }

+

{ t('common.Nothing matches your request') }

); } diff --git a/src/ui/common/pagination/index.tsx b/src/ui/common/pagination/index.tsx index 2dd241be..cffb9160 100644 --- a/src/ui/common/pagination/index.tsx +++ b/src/ui/common/pagination/index.tsx @@ -237,19 +237,19 @@ class PaginationComponent extends React.Component - Sort By + { t('common:label.sortBy') } { Object.keys(sortOptions).map((key, i) => { if (typeof sortOptions[key] === 'string') { return ( - { sortOptions[key] } + { t(sortOptions[key]) } ); } else { return ( - { sortOptions[key].label } + { t(sortOptions[key].label) } ); } diff --git a/src/ui/common/pie-chart/index.tsx b/src/ui/common/pie-chart/index.tsx index 63cc1e31..dff50547 100644 --- a/src/ui/common/pie-chart/index.tsx +++ b/src/ui/common/pie-chart/index.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import Slice from './Slice'; interface IPieProps extends React.ClassAttributes { @@ -7,6 +8,7 @@ interface IPieProps extends React.ClassAttributes { data: Array<{value: number, label: any}>; strokeColor?: string; strokeWidth?: string; + t: any; } const colors = [ [237, 194, 64], [175, 216, 248], [203, 75, 75], [77, 167, 77], [148, 64, 237]]; @@ -25,7 +27,7 @@ class Pie extends React.Component { } public render() { - const { radius = 100, holeRadius = 80, strokeColor = '#fff', strokeWidth = 1, data } = this.props; + const { radius = 100, holeRadius = 80, strokeColor = '#fff', strokeWidth = 1, data, t } = this.props; const diameter = radius * 2; const sum = data.reduce((accumulator, current) => accumulator + current.value, 0); let startAngle = 270; @@ -42,7 +44,7 @@ class Pie extends React.Component { { } } -export default Pie; +export default translate()(Pie); diff --git a/src/ui/common/snackbar/Snackbar.tsx b/src/ui/common/snackbar/Snackbar.tsx index 340c04ce..f1e530ec 100644 --- a/src/ui/common/snackbar/Snackbar.tsx +++ b/src/ui/common/snackbar/Snackbar.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import {connect} from 'react-redux'; import Snackbar_ from '@material-ui/core/Snackbar'; @@ -6,6 +7,7 @@ import Snackbar_ from '@material-ui/core/Snackbar'; interface ISnacks { snack: string; button?: any; + t: any; } /// Based on example from https://material-ui.com/demos/snackbars/#consecutive-snackbars @@ -73,15 +75,15 @@ class Snackbar extends React.Component { private renderContent = () => { const {messageInfo: {message} } = this.state; - const { button: renderButton } = this.props; + const { button: renderButton, t } = this.props; if (!renderButton) { - return ({ message }); + return ({ t(message) }); } return ( - { message } { renderButton() } + { t(message) } { renderButton() } ); @@ -111,4 +113,4 @@ const mapStateToProps = (state) => ({ button: state.snackbar.button, }); -export default connect(mapStateToProps, null)(Snackbar); +export default translate()(connect(mapStateToProps, null)(Snackbar)); diff --git a/src/ui/common/stepper/StepNavigation.tsx b/src/ui/common/stepper/StepNavigation.tsx index 016d5bc6..7fa2a181 100644 --- a/src/ui/common/stepper/StepNavigation.tsx +++ b/src/ui/common/stepper/StepNavigation.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import Grid from '@material-ui/core/Grid'; import Divider from '@material-ui/core/Divider'; @@ -24,6 +25,7 @@ interface IStepNavigationProps extends React.ClassAttributes { showStepName: boolean; topDivider: boolean; bottomDivider: boolean; + t: any; } const styles = (theme) => ({ @@ -83,13 +85,13 @@ class StepNavigation extends React.Component { } protected getItemActionButtons = () => { - const {itemState, disabled, onApprove, onPublish, onUnpublish, classes} = this.props; + const {itemState, disabled, onApprove, onPublish, onUnpublish, classes, t} = this.props; switch (itemState) { case PublishState.PUBLISHED: { return ( ); } @@ -97,11 +99,11 @@ class StepNavigation extends React.Component { return (
@@ -110,7 +112,7 @@ class StepNavigation extends React.Component { case PublishState.DRAFT: { return ( ); } @@ -119,7 +121,7 @@ class StepNavigation extends React.Component { public render() { - const {classes, disabled, disabledNext, steps, showStepName, topDivider, bottomDivider, onGotoStep, onDelete} = this.props; + const {classes, disabled, disabledNext, steps, showStepName, topDivider, bottomDivider, onGotoStep, onDelete, t} = this.props; const actionButtons = this.getItemActionButtons(); @@ -129,25 +131,25 @@ class StepNavigation extends React.Component {

{ - showStepName && `${this.state.id}. ${steps.find((e) => e.id === this.state.id).name}` + showStepName && `${this.state.id}. ${t(steps.find((e) => e.id === this.state.id).name)}` }

{ this.state.id === 1 && ( ) } { this.state.id > 1 && ( ) } { this.state.id !== steps.length && ( ) } { this.state.id === steps.length && actionButtons } @@ -159,4 +161,4 @@ class StepNavigation extends React.Component { } -export default withStyles(styles)(StepNavigation); +export default translate()(withStyles(styles)(StepNavigation)); diff --git a/src/ui/common/stepper/StepperTemplate.tsx b/src/ui/common/stepper/StepperTemplate.tsx index 6a2e1737..8a3b38d4 100644 --- a/src/ui/common/stepper/StepperTemplate.tsx +++ b/src/ui/common/stepper/StepperTemplate.tsx @@ -25,6 +25,7 @@ interface IStepperTemplateProps extends React.ClassAttributes { path: string; location: any; showHeader: boolean; + t: any; } class StepperTemplate extends React.Component { @@ -72,13 +73,13 @@ class StepperTemplate extends React.Component { public render() { - const {disabled, steps, stillLoading, pageTitle, path, location, showHeader} = this.props; + const {disabled, steps, stillLoading, pageTitle, path, location, showHeader, t} = this.props; const {disabledProgress} = this.state; const child = this.renderContent(); const stepNavigation = this.getStepNavigation(); return ( - { showHeader && } + { showHeader && } diff --git a/src/ui/common/stepper/progress-menu/index.tsx b/src/ui/common/stepper/progress-menu/index.tsx index bbdffae0..58bed5b9 100644 --- a/src/ui/common/stepper/progress-menu/index.tsx +++ b/src/ui/common/stepper/progress-menu/index.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import {withStyles} from '@material-ui/core/styles'; import List from '@material-ui/core/List'; import ListItem from '@material-ui/core/ListItem'; @@ -12,6 +13,7 @@ interface IProgressMenuProps extends React.ClassAttributes { location: any; steps: any; onGotoStep: (i: number) => void; + t: any; } const styleSheet = (theme) => ({ @@ -35,13 +37,13 @@ class ProgressMenu extends React.Component { public render() { - const {classes, disabled, steps, onGotoStep, location: {pathname}} = this.props; + const {classes, disabled, steps, onGotoStep, location: {pathname}, t} = this.props; const link = pathname.split('/').pop(); return ( - + { steps.map((step, i) => ( @@ -51,7 +53,7 @@ class ProgressMenu extends React.Component { onClick={ () => onGotoStep(i + 1) } active={ step.path.endsWith(link) } index={ i } - name = { step.name } + name = { t(step.name) } /> ), ) @@ -61,4 +63,4 @@ class ProgressMenu extends React.Component { } } -export default withStyles(styleSheet)(ProgressMenu); +export default translate()(withStyles(styleSheet)(ProgressMenu)); diff --git a/src/ui/common/tables/MyDataTable.tsx b/src/ui/common/tables/MyDataTable.tsx index 7b4b673a..3bc7f41d 100644 --- a/src/ui/common/tables/MyDataTable.tsx +++ b/src/ui/common/tables/MyDataTable.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import { translate } from 'react-i18next'; import Paper from '@material-ui/core/Paper'; import Grid from '@material-ui/core/Grid'; @@ -20,6 +21,7 @@ interface IMyDataTableProps extends React.Props { renderTableRow: (row, index) => any; sortOptions?: any; headerProps?: Array<{ title: any, width: string }>; + t: any; } const defaultSortOptions = { @@ -30,11 +32,11 @@ const defaultSortOptions = { const defaultHeaderProps = [ {title: 'No.', width: '10px'}, - {title: 'Title', width: '40%'}, - {title: 'Owner', width: null}, - {title: 'Created', width: null}, - {title: 'Modified', width: null}, - {title: 'Status', width: '90px'}, + {title: 'common:label.title', width: '40%'}, + {title: 'common:label.owner', width: null}, + {title: 'common:label.created', width: null}, + {title: 'common:label.modified', width: null}, + {title: 'common:label.status', width: '90px'}, ]; @@ -47,6 +49,7 @@ function MyDataTable({ renderTableRow, sortOptions = defaultSortOptions, headerProps = defaultHeaderProps, + t, }: IMyDataTableProps) { const loadNextPage = (page: number, pageSize: number) => { @@ -63,7 +66,7 @@ function MyDataTable({ prop.width) } headers={ ( - { headerProps.map((prop) => { prop.title }) } + { headerProps.map((prop) => { t(prop.title) }) } ) }> Date not provided); + return ({ t('common:label.dateNotProvided') }); } const year = value.substr(0, 4); @@ -28,4 +29,4 @@ export default function McpdDate({ value, locale = 'en-GB' }: { value: string, l { mcpdDate } ); -} +}); diff --git a/src/ui/common/time/PrettyDate.tsx b/src/ui/common/time/PrettyDate.tsx index 0444ffdc..7c5fbd74 100644 --- a/src/ui/common/time/PrettyDate.tsx +++ b/src/ui/common/time/PrettyDate.tsx @@ -1,11 +1,13 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import * as moment from 'moment'; import TimeAgo from 'react-time-ago'; -export default function PrettyDate({ +export default translate()(function PrettyDate({ value, -}: { value: Date }) { + t, +}: { value: Date, t: any }) { if (value) { const valueTime = value.getTime ? value.getTime() : new Date(value).getTime(); @@ -23,7 +25,7 @@ export default function PrettyDate({ ); } else { return ( - Date not provided + { t('common:label.dateNotProvided') } ); } -} +}); diff --git a/src/ui/genesys/LicenseSelector.tsx b/src/ui/genesys/LicenseSelector.tsx index 2ed311da..77cd8526 100644 --- a/src/ui/genesys/LicenseSelector.tsx +++ b/src/ui/genesys/LicenseSelector.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import { translate } from 'react-i18next'; import FormControlLabel from '@material-ui/core/FormControlLabel'; import FormLabel from '@material-ui/core/FormLabel'; @@ -13,9 +14,9 @@ const styles = { // None }; -const LicenseSelector = ({input, meta, classes, ...rest}) => ( +const LicenseSelector = ({input, meta, classes, t, ...rest}) => ( - Rights + { t('subsets.dashboard.p.stepper.basicInfo.rights') } ( ); -export default withStyles(styles)(LicenseSelector); +export default withStyles(styles)(translate()(LicenseSelector)); diff --git a/src/ui/layout/DashboardLayout.tsx b/src/ui/layout/DashboardLayout.tsx index 42146473..e84cf534 100644 --- a/src/ui/layout/DashboardLayout.tsx +++ b/src/ui/layout/DashboardLayout.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import { translate } from 'react-i18next'; // import DescriptorIcon from '@material-ui/icons/Description'; import DescriptorListIcon from '@material-ui/icons/List'; import AccountBoxIcon from '@material-ui/icons/AccountBox'; @@ -8,23 +9,23 @@ import MenuItem from 'ui/common/Menu'; import renderRoutes from 'ui/renderRoutes'; -const DashboardMenu = () => ( +const DashboardMenu = ({t}) => (
- }> - - + }> + + - }> - - + }> + +
); -const Layout = ({route, match}: { route: any, match: any}) => ( - }> +const Layout = ({route, match, t}: { route: any, match: any, t: any}) => ( + }> { renderRoutes(route.routes, match.path) } ); -export default Layout; +export default translate()(Layout); diff --git a/src/ui/layout/Footer/index.tsx b/src/ui/layout/Footer/index.tsx index f9eba5cc..91694512 100644 --- a/src/ui/layout/Footer/index.tsx +++ b/src/ui/layout/Footer/index.tsx @@ -18,36 +18,36 @@ const Footer = ({ t }) => (
  • - { t('footer.About Genesys') } + { t('common.footer.About Genesys') }
  • - { t('footer.Contact Us') } + { t('common.footer.Contact Us') }
  • - { t('footer.Disclaimer') } + { t('common.footer.Disclaimer') }
  • - { t('footer.Report an issue') } + { t('common.footer.Report an issue') }
  • - { t('footer.Source code') } + { t('common.footer.Source code') }
  • - { t('footer.Translate Genesys') } + { t('common.footer.Translate Genesys') }
  • - { t('footer.Terms and Conditions of Use') } + { t('common.footer.Terms and Conditions of Use') }
  • - { t('footer.Copyright policy') } + { t('common.footer.Copyright policy') }
  • - { t('footer.Privacy policy') } + { t('common.footer.Privacy policy') }

- { t('footer.copyright', { from: 2017, to: THIS_YEAR }) } + { t('common.footer.copyright', { from: 2017, to: THIS_YEAR }) }

diff --git a/src/ui/layout/Header/LeftMenu.tsx b/src/ui/layout/Header/LeftMenu.tsx index a0d460fe..83314624 100644 --- a/src/ui/layout/Header/LeftMenu.tsx +++ b/src/ui/layout/Header/LeftMenu.tsx @@ -111,19 +111,19 @@ class LeftMenu extends React.Component { - { t('menu.Home') } + { t('common.menu.Home') } - { t('menu.Accessions') } + { t('accessions.common.modelName_plural') } - { t('menu.Subsets') } + { t('subsets.common.modelName_plural') } - { t('menu.Institutes') } + { t('institutes.common.modelName_plural') } - { t('menu.Crops') } + { t('crop.common.modelName_plural') } diff --git a/src/ui/layout/Header/UserLoginMenu.tsx b/src/ui/layout/Header/UserLoginMenu.tsx index 504039c8..3047ac31 100644 --- a/src/ui/layout/Header/UserLoginMenu.tsx +++ b/src/ui/layout/Header/UserLoginMenu.tsx @@ -114,8 +114,8 @@ class UserLoginMenuComponent extends React.Component - {t('menu.login')} - {t('menu.register')} + {t('common.menu.login')} + {t('common.menu.register')} ); diff --git a/src/ui/layout/Header/UserMenuComponent.tsx b/src/ui/layout/Header/UserMenuComponent.tsx index 3296f55f..d6985dbb 100644 --- a/src/ui/layout/Header/UserMenuComponent.tsx +++ b/src/ui/layout/Header/UserMenuComponent.tsx @@ -112,9 +112,9 @@ class UserMenuComponent extends React.Component { onClick={ this.handleRequestClose } > - { t('menu.Admin') } + { t('common.menu.Admin') } - { t('menu.My Dashboard') } + { t('common.menu.My Dashboard') } { t('common:action.logout') } diff --git a/src/ui/layout/Header/index.tsx b/src/ui/layout/Header/index.tsx index d42596a5..12559842 100644 --- a/src/ui/layout/Header/index.tsx +++ b/src/ui/layout/Header/index.tsx @@ -173,12 +173,11 @@ class Header extends React.Component {
- { t('menu.Accessions') } - { t('menu.Subsets') } - Countries - { t('menu.Institutes') } - { t('menu.Crops') } - { t('menu.My List') } + { t('accessions.common.menu') } + { t('subsets.common.menu') } + { t('institutes.common.menu') } + { t('crop.common.menu') } + { t('list.common.menu') }
{ this.renderLogin([ROLE_USER, ROLE_ADMINISTRATOR]) }
diff --git a/src/ui/layout/PageLayout.tsx b/src/ui/layout/PageLayout.tsx index 4919a1ad..28d740c7 100644 --- a/src/ui/layout/PageLayout.tsx +++ b/src/ui/layout/PageLayout.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import { translate } from 'react-i18next'; import { withStyles } from '@material-ui/core/styles'; import Card, {CardHeader, CardContent} from 'ui/common/Card'; @@ -83,22 +84,22 @@ const Layout = ({classes, children = null, sidebar = null, withFooter = false}: ); const Contents = ({classes, children = null}) => children &&
{ children }
; -const Section1 = ({classes, title, children = null}) => children && ( +const Section1 = ({classes, title, children = null, t}) => children && ( - + { children } ); -const Section2 = ({classes, title, children = null}) => children && ( +const Section2 = ({classes, title, children = null, t}) => children && ( - + { children } ); export const PageContents = withStyles(styles)(Contents); -export const MainSection = withStyles(styles)(Section1); -export const PageSection = withStyles(styles)(Section2); +export const MainSection = translate()(withStyles(styles)(Section1)); +export const PageSection = translate()(withStyles(styles)(Section2)); export default withStyles(styles)(Layout); diff --git a/src/ui/pages/_base/StepperPage.tsx b/src/ui/pages/_base/StepperPage.tsx index 3d14de68..45cd6603 100644 --- a/src/ui/pages/_base/StepperPage.tsx +++ b/src/ui/pages/_base/StepperPage.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; @@ -30,6 +31,7 @@ interface IStepperProps extends React.ClassAttributes { setPageTitle: (title: string) => void; route: any; match: any; + t: any; } class StepperTemplate extends React.Component & P, any> { @@ -107,7 +109,7 @@ class StepperTemplate extends React.Component & P, any> { } public render() { - const {uuid, pageTitle, route, match, steps, path, location, needLoading = true, showHeader = true} = this.props; + const {uuid, pageTitle, route, match, steps, path, location, needLoading = true, showHeader = true, t} = this.props; const {item} = this.props; const stillLoading: boolean = needLoading && (!item || (uuid && (item.uuid !== uuid))); const disabled: boolean = needLoading && !(item && item.uuid); @@ -125,6 +127,7 @@ class StepperTemplate extends React.Component & P, any> { pageTitle, disabled, showHeader, + t, onDelete: this.onDelete, onPublish: this.onPublish, onUnpublish: this.onUnpublish, @@ -149,5 +152,5 @@ const mapDispatchToProps = (dispatch) => bindActionCreators({ setPageTitle, }, dispatch); -export default connect(mapStateToProps, mapDispatchToProps)(StepperTemplate); +export default translate()(connect(mapStateToProps, mapDispatchToProps)(StepperTemplate)); export {StepperTemplate as BaseStepperPage}; diff --git a/src/ui/pages/welcome/index.tsx b/src/ui/pages/welcome/index.tsx index 1b1de3c6..80682bac 100644 --- a/src/ui/pages/welcome/index.tsx +++ b/src/ui/pages/welcome/index.tsx @@ -231,7 +231,7 @@ class WelcomePage extends React.Component { constructor(props: any, context: any) { super(props, context); const { t } = props; - this.state = { query: '', queryPlaceholder: t('welcome.search.placeholder') }; + this.state = { query: '', queryPlaceholder: t('public.p.welcome.search.placeholder') }; } public render() { @@ -266,14 +266,14 @@ class WelcomePage extends React.Component { } else { this.setState({ ...this.state, - queryPlaceholder: t(`welcome.search.suggestion${Math.floor(Math.random() * SEARCH_SUGGESTIONS_COUNT)}`), + queryPlaceholder: t(`public.p.welcome.search.suggestion${Math.floor(Math.random() * SEARCH_SUGGESTIONS_COUNT)}`), }); } }; return ( - +
@@ -309,7 +309,7 @@ class WelcomePage extends React.Component { - { t('stats.Accessions', { count: serverInfo.accessionCount }) } + { t('accessions.common.stats', { count: serverInfo.accessionCount }) } @@ -317,7 +317,7 @@ class WelcomePage extends React.Component { - { t('stats.Subsets', { count: serverInfo.subsetCount }) } + { t('subsets.common.stats', { count: serverInfo.subsetCount }) } @@ -325,7 +325,7 @@ class WelcomePage extends React.Component { - { t('stats.Phenotypic datasets', { count: serverInfo.datasetCount }) } + { t('datasets.common.stats', { count: serverInfo.datasetCount }) } @@ -333,7 +333,7 @@ class WelcomePage extends React.Component { - { t('stats.Institutes', { count: serverInfo.instituteCount }) } + { t('institutes.common.stats', { count: serverInfo.instituteCount }) } @@ -342,28 +342,28 @@ class WelcomePage extends React.Component { - { t('stats.Accessions', { count: serverInfo.accessionCount }) } + { t('accessions.common.stats', { count: serverInfo.accessionCount }) } - { t('stats.Subsets', { count: serverInfo.subsetCount }) } + { t('subsets.common.stats', { count: serverInfo.subsetCount }) } - { t('stats.Phenotypic datasets', { count: serverInfo.datasetCount }) } + { t('datasets.common.stats', { count: serverInfo.datasetCount }) } - { t('stats.Institutes', { count: serverInfo.instituteCount }) } + { t('institutes.common.stats', { count: serverInfo.instituteCount }) } @@ -395,7 +395,7 @@ share caracterization and evaluation information on material held in their colle -

{ t('welcome.Contribute to Genesys') }

+

{ t('public.p.welcome.Contribute to Genesys') }

@@ -410,7 +410,7 @@ share caracterization and evaluation information on material held in their colle -

{ t('welcome.Subscribe to Newsletter') }

+

{ t('public.p.welcome.Subscribe to Newsletter') }

@@ -419,13 +419,13 @@ share caracterization and evaluation information on material held in their colle -

{ t('welcome.Bookmark this page') }

+

{ t('public.p.welcome.Bookmark this page') }

-

{ t('welcome.About Genesys PGR') }

+

{ t('public.p.welcome.About Genesys PGR') }

diff --git a/src/user/translations.json b/src/user/translations.json new file mode 100644 index 00000000..26c49f92 --- /dev/null +++ b/src/user/translations.json @@ -0,0 +1,115 @@ +{ + "public": { + "c": { + "loginForm": { + "userName": "Username", + "password": "Password", + "googleLogin": "Login with Google", + "login": "Login" + }, + "registrationForm": { + "password": "Password", + "passwordConfirm": "Repeat password", + "fullName": "Your full name", + "register": "Register" + }, + "userProfileCard": { + "accountExpires": "Account expires", + "lastLogin": "Last login", + "accountLocked": "Account locked:", + "lockedUntil": "Locked until:", + "accountActive": "Account active:" + } + }, + "p": { + "login": { + "title": "Welcome to Genesys", + "subTitle": "Log in to manage datasets" + }, + "registration": { + "title": "Create your account", + "register": "Register a new account" + } + } + }, + "admin": { + "f": { + "title": "Filter users", + "locked": "Account locked", + "enabled": "Account active", + "expired": "Account expired" + }, + "p": { + "browse": { + "title": "Registered user accounts" + }, + "display": { + "title": "User profile information", + "unlock": "Unlock", + "lock": "Lock", + "disable": "Disable", + "enable": "Enable", + "sendEmail": "Send validation E-mail" + }, + "edit": { + "title": "Update user profile" + } + } + }, + "dashboard": { + "c": { + "passwordForm": { + "newPassword": "New password", + "oldPassword": "Old password", + "confirmPassword": "Confirm password", + "changePassword": "Change password" + } + }, + "menu": { + "profile": "Profile", + "userProfile": "User profile", + "changePassword": "Change password" + }, + "p": { + "changePassword": { + "unableChange": "You can't set your password if you use Google auth", + "title": "Password change" + }, + "profile": { + "title": "User profile" + } + } + }, + "common": { + "email": "Email", + "emailAddress": "E-mail address", + "name": "Name", + "fullName": "Full name", + "surname": "Surname", + "country": "Country", + "phone": "Phone", + "statusLabel": "Status", + "status": { + "locked": "Locked", + "enabled": "Active", + "expired": "Expired" + }, + "roleLabel": "User roles", + "role": { + "USER": "User", + "ADMINISTRATOR": "Administrator", + "EVERYONE": "Everyone", + "VALIDATEDUSER": "Validated user", + "VETTEDUSER": "Vetted user", + "CONTENTMANAGER": "Content manager" + }, + "typeLabel": "Account type", + "type": { + "local": "LOCAL", + "google": "GOOGLE", + "system": "SYSTEM", + "deleted": "DELETED", + "ldap": "LDAP" + } + } +} \ No newline at end of file diff --git a/src/user/ui/LoginPage.tsx b/src/user/ui/LoginPage.tsx index ae228e1b..c5554caa 100644 --- a/src/user/ui/LoginPage.tsx +++ b/src/user/ui/LoginPage.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; import * as _ from 'lodash'; @@ -21,6 +22,7 @@ interface ILoginContainerProps extends React.ClassAttributes { verifyGoogleTokenRequest: (aT) => Promise; history: any; googleClientId: string; + t: any; } class LoginContainer extends React.Component { @@ -64,13 +66,14 @@ class LoginContainer extends React.Component { } public render() { + const {t} = this.props; return ( - + - + @@ -93,4 +96,4 @@ const mapDispatchToProps = (dispatch) => bindActionCreators({ verifyGoogleTokenRequest, }, dispatch); -export default connect(mapStateToProps, mapDispatchToProps)(LoginContainer); +export default translate()(connect(mapStateToProps, mapDispatchToProps)(LoginContainer)); diff --git a/src/user/ui/RegistrationPage.tsx b/src/user/ui/RegistrationPage.tsx index a17716aa..cb5308f8 100644 --- a/src/user/ui/RegistrationPage.tsx +++ b/src/user/ui/RegistrationPage.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import {connect} from 'react-redux'; import {bindActionCreators} from 'redux'; @@ -20,6 +21,7 @@ interface ILoginContainerProps extends React.ClassAttributes { checkTokenRequest: (t) => Promise; history: any; captchaClientKey: string; + t: any; } class LoginContainer extends React.Component { @@ -43,14 +45,14 @@ class LoginContainer extends React.Component { public render() { const { errorMsg } = this.state; - const { captchaClientKey } = this.props; + const { captchaClientKey, t } = this.props; return ( - + - + @@ -70,4 +72,4 @@ const mapDispatchToProps = (dispatch) => bindActionCreators({ registrationRequest, }, dispatch); -export default connect(mapStateToProps, mapDispatchToProps)(LoginContainer); +export default translate()(connect(mapStateToProps, mapDispatchToProps)(LoginContainer)); diff --git a/src/user/ui/admin/BrowsePage.tsx b/src/user/ui/admin/BrowsePage.tsx index 30f38ff5..353f6596 100644 --- a/src/user/ui/admin/BrowsePage.tsx +++ b/src/user/ui/admin/BrowsePage.tsx @@ -59,7 +59,7 @@ class BrowsePage extends BrowsePageTemplate { - + { return user === null ? () : (
- { user.accountLocked ? lockAccount(user.uuid, false) }/> - : lockAccount(user.uuid) }/> + { user.accountLocked ? lockAccount(user.uuid, false) }/> + : lockAccount(user.uuid) }/> } - { user.active ? enableAccount(user.uuid, false) }/> - : enableAccount(user.uuid) }/> + { user.active ? enableAccount(user.uuid, false) }/> + : enableAccount(user.uuid) }/> } - sendVerificationEmail(user.uuid) }/> - deleteAccount(user.uuid) }/> - navigateTo(`/admin/users/${user.uuid}/edit`) }/> - + sendVerificationEmail(user.uuid) }/> + deleteAccount(user.uuid) }/> + navigateTo(`/admin/users/${user.uuid}/edit`) }/> +
} /> diff --git a/src/user/ui/admin/EditUserPage.tsx b/src/user/ui/admin/EditUserPage.tsx index d9f93169..7b887c72 100644 --- a/src/user/ui/admin/EditUserPage.tsx +++ b/src/user/ui/admin/EditUserPage.tsx @@ -66,7 +66,7 @@ class EditUserPage extends React.Component { return user === null ? () : (
- + diff --git a/src/user/ui/admin/c/UserCard.tsx b/src/user/ui/admin/c/UserCard.tsx index be2603f4..d1370534 100644 --- a/src/user/ui/admin/c/UserCard.tsx +++ b/src/user/ui/admin/c/UserCard.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import {withStyles} from '@material-ui/core/styles'; import {UserLink} from 'ui/genesys/Links'; @@ -15,7 +16,7 @@ const styles = () => ({ }, }); -const UserCard = ({user, classes, index, ...other}: { user: User, classes: any, index?: number } & React.ClassAttributes) => { +const UserCard = ({user, classes, index, t, ...other}: { user: User, classes: any, index?: number, t: any } & React.ClassAttributes) => { if (! user) { console.log('Null user for UserCard'); @@ -38,13 +39,13 @@ const UserCard = ({user, classes, index, ...other}: { user: User, classes: any, { user.fullName }
- { user.roles.map((r, i) => { i > 0 ? ' • ' : '' } { r }) } - { user.accountLocked && Locked } - { user.accountExpired && Expired } + { user.roles.map((r, i) => { i > 0 ? ' • ' : '' } { t(`user.common.role.${r.toUpperCase()}`) }) } + { user.accountLocked && { t('user.common.status.locked') } } + { user.accountExpired && { t('user.common.status.expired') } }
); }; -export default withStyles(styles)(UserCard); +export default translate()(withStyles(styles)(UserCard)); diff --git a/src/user/ui/admin/c/UserFilter.tsx b/src/user/ui/admin/c/UserFilter.tsx index 408a0887..89f39b52 100644 --- a/src/user/ui/admin/c/UserFilter.tsx +++ b/src/user/ui/admin/c/UserFilter.tsx @@ -12,18 +12,18 @@ import {User} from 'model/user/User'; const UserFilters = ({handleSubmit, initialValues, initialize, ...other}) => { return ( - - - - + + + + - + - - - - + + + + ); diff --git a/src/user/ui/admin/c/UserForm.tsx b/src/user/ui/admin/c/UserForm.tsx index d05d72e2..88d34d5f 100644 --- a/src/user/ui/admin/c/UserForm.tsx +++ b/src/user/ui/admin/c/UserForm.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import {Field, reduxForm, FieldArray} from 'redux-form'; // Util @@ -8,7 +9,7 @@ import Validators from 'utilities/Validators'; import {ADMIN_UPDATE_USER_FORM} from 'user/ui/constants'; // Model -import {UserRole} from 'model/user/User'; +import {User, UserRole} from 'model/user/User'; // UI import Grid from '@material-ui/core/Grid'; @@ -29,7 +30,7 @@ const handleCheckboxChange = (fields, role) => () => { } }; -const renderRoles = ({fields, label}) => ( +const renderRoles = ({fields, label, t}) => ( { label } @@ -44,7 +45,7 @@ const renderRoles = ({fields, label}) => ( value={ UserRole[key] } /> } - label={ UserRole[key] } + label={ t(User.USERROLES[key]) } /> )) @@ -67,31 +68,32 @@ class UserForm extends React.Component { { error &&
{ error }
} - - + + ); } } -export default reduxForm({ +export default translate()(reduxForm({ form: ADMIN_UPDATE_USER_FORM, enableReinitialize: true, -})(UserForm); +})(UserForm)); diff --git a/src/user/ui/c/LoginForm.tsx b/src/user/ui/c/LoginForm.tsx index 68dd998d..3e71c683 100644 --- a/src/user/ui/c/LoginForm.tsx +++ b/src/user/ui/c/LoginForm.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import {withStyles} from '@material-ui/core/styles'; import TextField from '@material-ui/core/TextField'; @@ -21,6 +22,7 @@ interface ILoginProps extends React.ClassAttributes { onTryLogin: (username, password) => Promise; onTryGoogleLogin: (response) => Promise; googleClientId: string; + t: any; } class Login extends React.Component { @@ -66,18 +68,18 @@ class Login extends React.Component { private handlePassword = (e) => this.setState({...this.state, password: e.target.value}); public render() { - const { classes, googleClientId } = this.props; + const { classes, googleClientId, t } = this.props; return (
{ { this.state.error &&
{ this.state.errorDescription }
} { googleClientId && } @@ -104,4 +106,4 @@ class Login extends React.Component { } -export default withStyles(styles)(Login); +export default translate()(withStyles(styles)(Login)); diff --git a/src/user/ui/c/RegistrationForm.tsx b/src/user/ui/c/RegistrationForm.tsx index 734d1704..04b4a0f3 100644 --- a/src/user/ui/c/RegistrationForm.tsx +++ b/src/user/ui/c/RegistrationForm.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; import ReCAPTCHA from 'react-google-recaptcha'; import {Field, reduxForm} from 'redux-form'; // Constants @@ -24,6 +25,7 @@ interface IRegistrationProps extends React.ClassAttributes { handleSubmit: any; errorMsg: string; captchaClientKey: string; + t: any; } class Registration extends React.Component { @@ -33,12 +35,12 @@ class Registration extends React.Component { }; public render() { - const {handleSubmit, captchaClientKey, errorMsg} = this.props; + const {handleSubmit, captchaClientKey, errorMsg, t} = this.props; return ( { /> { /> { /> { { errorMsg &&
{ errorMsg }
} @@ -96,7 +98,7 @@ const validate = (values) => { return {}; }; -export default reduxForm({ +export default translate()(reduxForm({ form: REGISTRATION_FORM, enableReinitialize: true, validate, -})(Registration); +})(Registration)); diff --git a/src/user/ui/c/UserProfileCard.tsx b/src/user/ui/c/UserProfileCard.tsx index d68e0331..7e203f5b 100644 --- a/src/user/ui/c/UserProfileCard.tsx +++ b/src/user/ui/c/UserProfileCard.tsx @@ -1,4 +1,5 @@ import * as React from 'react'; +import {translate} from 'react-i18next'; // UI import Card, {CardHeader, CardContent} from 'ui/common/Card'; @@ -9,7 +10,7 @@ import Grid from '@material-ui/core/Grid'; // Model import {User} from 'model/user/User'; -const UserProfileCard = ({userProfile, admin = false, ...other}: { userProfile: User, admin?: boolean } & React.ClassAttributes) => { +const UserProfileCard = ({userProfile, admin = false, t, ...other}: { userProfile: User, admin?: boolean, t: any} & React.ClassAttributes) => { return (
@@ -18,19 +19,19 @@ const UserProfileCard = ({userProfile, admin = false, ...other}: { userProfile: - { userProfile.fullName || Not specified } - { userProfile.email } - { userProfile.accountType } - { - userProfile.roles.map((role) => (
{ role }
)) + { userProfile.fullName || Not specified } + { userProfile.email } + { t(`user.common.type.${userProfile.accountType.toLowerCase()}`) } + { + userProfile.roles.map((role) => (
{ t(`user.common.role.${role}`) }
)) }
- + { admin && userProfile.lastLogin && - } - { admin && { userProfile.accountLocked ? `Yes` : `No` } } + } + { admin && { userProfile.accountLocked ? t('common:label.yes') : t('common:label.no') } } { admin && userProfile.accountLocked && userProfile.lockedUntil && - } - { admin && { userProfile.active ? `Yes` : `No` } } + } + { admin && { userProfile.active ? t('common:label.yes') : t('common:label.no') } }
@@ -40,4 +41,4 @@ const UserProfileCard = ({userProfile, admin = false, ...other}: { userProfile: ); }; -export default UserProfileCard; +export default translate()(UserProfileCard); diff --git a/src/user/ui/dashboard/ChangePasswordPage.tsx b/src/user/ui/dashboard/ChangePasswordPage.tsx index 8683047c..9485f1e4 100644 --- a/src/user/ui/dashboard/ChangePasswordPage.tsx +++ b/src/user/ui/dashboard/ChangePasswordPage.tsx @@ -56,14 +56,14 @@ class ChangePasswordPage extends React.Component {
{ userProfile.accountType === AccountType.LOCAL ?
- +
- : + : }
} diff --git a/src/user/ui/dashboard/ProfilePage.tsx b/src/user/ui/dashboard/ProfilePage.tsx index 091255b1..b2fb9e21 100644 --- a/src/user/ui/dashboard/ProfilePage.tsx +++ b/src/user/ui/dashboard/ProfilePage.tsx @@ -47,7 +47,7 @@ class UserProfile extends React.Component {
{ stillLoading ? :
- +
} diff --git a/src/user/ui/dashboard/c/PasswordForm.tsx b/src/user/ui/dashboard/c/PasswordForm.tsx index c8507090..3e8eadc8 100644 --- a/src/user/ui/dashboard/c/PasswordForm.tsx +++ b/src/user/ui/dashboard/c/PasswordForm.tsx @@ -19,27 +19,27 @@ class PasswordForm extends React.Component { { error &&
{ error }
} ); -- GitLab