diff --git a/packages/client/public/locales/en/translation.json b/packages/client/public/locales/en/translation.json index ccc51111..1a4631d1 100644 --- a/packages/client/public/locales/en/translation.json +++ b/packages/client/public/locales/en/translation.json @@ -5,7 +5,22 @@ "instruction": "Instruction", "project": "Project", "study": "Study", - "submit": "Submit" + "submit": "Submit", + "delete": "Delete", + "cancel": "Cancel", + "ok": "OK", + "email": "Email", + "back": "Back", + "finish": "Finish", + "next": "Next", + "continue": "Continue", + "required": "Required", + "preview": "Preview", + "enable": "Enable", + "view": "View", + "entryId": "Entry ID", + "login": "Login", + "clear": "clear" }, "languages": { "en": "English", @@ -24,7 +39,7 @@ "studies": "Studies", "newStudy": "New Study", "studyControl": "Study Control", - "entryControls": "Entry Controls", + "entryControl": "Entry Control", "downloadTags": "Download Tags", "datasets": "Datasets", "datasetControl": "Dataset Control", @@ -44,7 +59,64 @@ "formLabel": "Create New Project", "nameDescription": "Please enter project name", "descriptionDescription": "Please enter project description", + "failMessage": " Failed to create project! Try again.", + "projectExists": "A project with this name already exists" + }, + "projectControl": { + "deleteStudy": "Delete Study", + "deleteDescription": "Are you sure you want to delete this project? Doing so will delete all contained studies and tags" + }, + "datasetControl": { + "deleteEntry": "Delete Entry", + "deleteDescription": "Are you sure you want to delete this project? Doing so will delete all associated tags", + "addDataset": " Add New Dataset", + "uploadEntries": " Upload Entries" + }, + "projectAccess": { + "datasetName": "Dataset Name", + "projectHasAccess": "Project Has Access", + "accessFor": "Dataset Access for ", + "selectProject": "Select a Project to Continue" + }, + "userPermissions": { + "studyAdmin": "Study Admin", + "contributor": "Contributor", + "trained": "Trained" + }, + "projectUserPermissions": { + "projectAdmin": "Project Admin", + "contributor": "Contributor", + "trained": "Trained" + }, + "newStudy": { + "createStudy": "Create New Study", + "steps": { + "Study Identification": "Study Identification", + "Construct Tagging Interface": "Construct Tagging Interface", + "Select Tag Training Items": "Select Tag Training Items" + }, + "completed": "All steps completed - your new study is created", + "startOver": "Start Over", + "formTitle": "Study Information", + "tagsDescription": "Number of times each entry needs to be tagged (default 1)" + }, + "studyControl": { + "deleteStudy": "Delete Study", + "deleteDescription": "Are you sure you want to delete this study? Doing so will delete all contained tags" + }, + "contribute": { + "enterTagging": "Enter tagging", + "noTaggingLeft": "No tagging left", + "studyTraining": "Study Training", + "studyTagging": "Study Tagging", "failMessage": " Failed to create project! Try again." + }, + "successPage": { + "succefullyCreated": "Successfully created!" + }, + "login": { + "selectOrg": "Select an Organization to Login", + "redirectToOrg": "Redirect to Organization Login" } } } diff --git a/packages/client/src/components/DatasetAccess.component.tsx b/packages/client/src/components/DatasetAccess.component.tsx index b1f0ea36..cf6d5c00 100644 --- a/packages/client/src/components/DatasetAccess.component.tsx +++ b/packages/client/src/components/DatasetAccess.component.tsx @@ -3,6 +3,7 @@ import useEnhancedEffect from '@mui/material/utils/useEnhancedEffect'; import { DataGrid, GridColDef, GridRenderCellParams, useGridApiContext } from '@mui/x-data-grid'; import { GridRowModesModel } from '@mui/x-data-grid-pro'; import { useRef, useState } from 'react'; +import { useTranslation } from 'react-i18next'; interface Row { id: number; @@ -41,6 +42,7 @@ const renderSwitchEditInputCell: GridColDef['renderCell'] = (params) => { export const DatasetAccess: React.FC = ({ tableRows }: Table) => { const [rows] = useState(tableRows); const [rowModesModel, setRowModesModel] = useState({}); + const { t } = useTranslation(); const handleRowModesModelChange = (newRowModesModel: GridRowModesModel) => { setRowModesModel(newRowModesModel); @@ -50,20 +52,20 @@ export const DatasetAccess: React.FC
= ({ tableRows }: Table) => { { field: 'id', headerName: 'ID', width: 55 }, { field: 'name', - headerName: 'Name', + headerName: t('common.name'), width: 200, editable: true }, { field: 'description', - headerName: 'Description', + headerName: t('common.description'), width: 450, editable: true }, { field: 'switch', type: 'boolean', - headerName: 'Project Access', + headerName: t('menu.projectAccess'), renderCell: (params) => , renderEditCell: renderSwitchEditInputCell, editable: true, diff --git a/packages/client/src/components/DatasetTable.component.tsx b/packages/client/src/components/DatasetTable.component.tsx index f2ef5c46..4fc93808 100644 --- a/packages/client/src/components/DatasetTable.component.tsx +++ b/packages/client/src/components/DatasetTable.component.tsx @@ -3,6 +3,7 @@ import { useState, useEffect } from 'react'; import { Dataset, Entry } from '../graphql/graphql'; import { useEntryForDatasetLazyQuery } from '../graphql/entry/entry'; import { EntryView } from './EntryView.component'; +import { useTranslation } from 'react-i18next'; export interface DatasetTableProps { dataset: Dataset; @@ -10,16 +11,18 @@ export interface DatasetTableProps { } export const DatasetTable: React.FC = (props) => { + const { t } = useTranslation(); + const defaultColumns: GridColDef[] = [ { field: 'view', - headerName: 'View', + headerName: t('common.view'), width: 300, renderCell: (params) => }, { field: 'entryID', - headerName: 'Entry ID', + headerName: t('common.entryId'), width: 150, editable: false } diff --git a/packages/client/src/components/NewStudyJsonForm.component.tsx b/packages/client/src/components/NewStudyJsonForm.component.tsx index c40460b5..c4895a89 100644 --- a/packages/client/src/components/NewStudyJsonForm.component.tsx +++ b/packages/client/src/components/NewStudyJsonForm.component.tsx @@ -5,6 +5,7 @@ import { PartialStudyCreate } from '../types/study'; import { ErrorObject } from 'ajv'; import { useStudyExistsLazyQuery } from '../graphql/study/study'; import { useProject } from '../context/Project.context'; +import { useTranslation } from 'react-i18next'; export interface NewStudyFormProps { newStudy: PartialStudyCreate | null; @@ -12,11 +13,6 @@ export interface NewStudyFormProps { } export const NewStudyJsonForm: React.FC = (props) => { - const initialData = { - tagsPerEntry: schema.properties.tagsPerEntry.default - }; - - const [data, setData] = useState(initialData); const [studyExistsQuery, studyExistsResults] = useStudyExistsLazyQuery(); const { project } = useProject(); const [additionalErrors, setAdditionalErrors] = useState([]); @@ -24,6 +20,60 @@ export const NewStudyJsonForm: React.FC = (props) => { // Keep track of the new study internally to check to make sure the name is // unique before submitting const [potentialNewStudy, setPotentialNewStudy] = useState(null); + const { t } = useTranslation(); + + const schema = { + type: 'object', + properties: { + name: { + type: 'string', + pattern: '^[a-zA-Z 0-9]*$' + }, + description: { + type: 'string' + }, + instructions: { + type: 'string' + }, + tagsPerEntry: { + type: 'number', + default: 1 + } + }, + required: ['name', 'description', 'instructions', 'tagsPerEntry'] + }; + + const uischema = { + type: 'Group', + label: t('components.newStudy.formTitle'), + elements: [ + { + type: 'Control', + label: t('common.name'), + scope: '#/properties/name' + }, + { + type: 'Control', + label: t('common.description'), + scope: '#/properties/description' + }, + { + type: 'Control', + label: t('common.instruction'), + scope: '#/properties/instructions' + }, + { + type: 'Control', + label: t('components.newStudy.tagsDescription'), + scope: '#/properties/tagsPerEntry' + } + ] + }; + + const initialData = { + tagsPerEntry: schema.properties.tagsPerEntry.default + }; + const [data, setData] = useState(initialData); const handleChange = (data: any, errors: ErrorObject[] | undefined) => { setData(data); @@ -68,51 +118,3 @@ export const NewStudyJsonForm: React.FC = (props) => { /> ); }; - -const schema = { - type: 'object', - properties: { - name: { - type: 'string', - pattern: '^[a-zA-Z 0-9]*$' - }, - description: { - type: 'string' - }, - instructions: { - type: 'string' - }, - tagsPerEntry: { - type: 'number', - default: 1 - } - }, - required: ['name', 'description', 'instructions', 'tagsPerEntry'] -}; - -const uischema = { - type: 'Group', - label: 'Study Information', - elements: [ - { - type: 'Control', - label: 'Name', - scope: '#/properties/name' - }, - { - type: 'Control', - label: 'Description', - scope: '#/properties/description' - }, - { - type: 'Control', - label: 'Instructions', - scope: '#/properties/instructions' - }, - { - type: 'Control', - label: 'Number of times each entry needs to be tagged (default 1)', - scope: '#/properties/tagsPerEntry' - } - ] -}; diff --git a/packages/client/src/components/SideBar.component.tsx b/packages/client/src/components/SideBar.component.tsx index 98dde7ca..5144739d 100644 --- a/packages/client/src/components/SideBar.component.tsx +++ b/packages/client/src/components/SideBar.component.tsx @@ -62,7 +62,7 @@ export const SideBar: FC = ({ open, drawerWidth }) => { action: () => navigate('/study/permissions'), visible: (p) => p!.studyAdmin }, - { name: t('menu.entryControls'), action: () => navigate('/study/entries'), visible: (p) => p!.studyAdmin }, + { name: t('menu.entryControl'), action: () => navigate('/study/entries'), visible: (p) => p!.studyAdmin }, { name: t('menu.downloadTags'), action: () => navigate('/study/tags'), visible: (p) => p!.studyAdmin } ] }, diff --git a/packages/client/src/components/contribute/TagForm.component.tsx b/packages/client/src/components/contribute/TagForm.component.tsx index f4c62151..98da1e16 100644 --- a/packages/client/src/components/contribute/TagForm.component.tsx +++ b/packages/client/src/components/contribute/TagForm.component.tsx @@ -8,6 +8,7 @@ import AslLexSearchControl from '../tag/asllex/AslLexSearchControl'; import AslLexSearchControlTester from '../tag/asllex/aslLexSearchControlTester'; import VideoRecordField, { videoFieldTester } from '../tag/videorecord/VideoRecordField.component'; import { JsonFormsRendererRegistryEntry } from '@jsonforms/core'; +import { useTranslation } from 'react-i18next'; export interface TagFormProps { study: Study; @@ -17,6 +18,7 @@ export interface TagFormProps { export const TagForm: React.FC = (props) => { const [data, setData] = useState(); const [dataValid, setDataValid] = useState(false); + const { t } = useTranslation(); const handleFormChange = (data: any, errors: ErrorObject[] | undefined) => { setData(data); @@ -62,10 +64,10 @@ export const TagForm: React.FC = (props) => { /> diff --git a/packages/client/src/context/Confirmation.context.tsx b/packages/client/src/context/Confirmation.context.tsx index 057099e1..8854ca22 100644 --- a/packages/client/src/context/Confirmation.context.tsx +++ b/packages/client/src/context/Confirmation.context.tsx @@ -1,5 +1,6 @@ import { createContext, useContext, useState } from 'react'; import { Dialog, DialogContent, DialogTitle, DialogActions, Button, Typography } from '@mui/material'; +import { useTranslation } from 'react-i18next'; export interface ConfirmationRequest { message: string; @@ -21,6 +22,7 @@ export interface ConfirmationProviderProps { export const ConfirmationProvider: React.FC = ({ children }) => { const [open, setOpen] = useState(false); const [confirmationRequest, setConfirmationRequest] = useState(null); + const { t } = useTranslation(); const pushConfirmationRequest = (confirmationRequest: ConfirmationRequest) => { setConfirmationRequest(confirmationRequest); @@ -50,9 +52,9 @@ export const ConfirmationProvider: React.FC = ({ chil - + {children} diff --git a/packages/client/src/pages/LoginPage.tsx b/packages/client/src/pages/LoginPage.tsx index 6abdbce3..79ebf88d 100644 --- a/packages/client/src/pages/LoginPage.tsx +++ b/packages/client/src/pages/LoginPage.tsx @@ -4,11 +4,13 @@ import { useAuth } from '../context/Auth.context'; import { useNavigate } from 'react-router-dom'; import { Organization } from '../graphql/graphql'; import { useGetOrganizationsQuery } from '../graphql/organization/organization'; +import { useTranslation } from 'react-i18next'; export const LoginPage: FC = () => { // Construct the Auth URL const { authenticated } = useAuth(); const navigate = useNavigate(); + const { t } = useTranslation(); const [organization, setOrganization] = useState(null); const [authURL, setAuthURL] = useState(null); @@ -62,7 +64,7 @@ export const LoginPage: FC = () => { alignItems: 'center' }} > - Login + {t('common.login')} diff --git a/packages/client/src/pages/SuccessPage.tsx b/packages/client/src/pages/SuccessPage.tsx index 3ac27e80..82076a3c 100644 --- a/packages/client/src/pages/SuccessPage.tsx +++ b/packages/client/src/pages/SuccessPage.tsx @@ -1,11 +1,14 @@ import { Typography, Button } from '@mui/material'; +import { useTranslation } from 'react-i18next'; export const SuccessPage = () => { + const { t } = useTranslation(); + return (
- Successfully created! + {t('components.successPage.succefullyCreated')}
); diff --git a/packages/client/src/pages/contribute/ContributeLanding.tsx b/packages/client/src/pages/contribute/ContributeLanding.tsx index 5272fd17..d57b7241 100644 --- a/packages/client/src/pages/contribute/ContributeLanding.tsx +++ b/packages/client/src/pages/contribute/ContributeLanding.tsx @@ -2,11 +2,13 @@ import { Typography, Box, Stack, Button } from '@mui/material'; import { useNavigate } from 'react-router-dom'; import { useStudy } from '../../context/Study.context'; import { TagProvider, useTag } from '../../context/Tag.context'; +import { useTranslation } from 'react-i18next'; const ContributeLandingInternal: React.FC = () => { const navigate = useNavigate(); const { study } = useStudy(); const { tag } = useTag(); + const { t } = useTranslation(); const enterTagging = () => { navigate('/contribute/tagging'); @@ -18,17 +20,27 @@ const ContributeLandingInternal: React.FC = () => { <> {study && ( - Study: {study.name} + + {t('common.study')}: {study.name} + - {false ? 'Study Training' : 'Study Tagging'} - Study: {study.name} - Description: {study.description} - Instructions: {study.instructions} + + {false ? t('components.contribute.studyTraining') : t('components.contribute.studyTagging')} + + + {t('common.study')}: {study.name} + + + {t('common.description')}: {study.description} + + + {t('common.instruction')}: {study.instructions} + )} diff --git a/packages/client/src/pages/datasets/DatasetControls.tsx b/packages/client/src/pages/datasets/DatasetControls.tsx index 44164ab5..a66f93c5 100644 --- a/packages/client/src/pages/datasets/DatasetControls.tsx +++ b/packages/client/src/pages/datasets/DatasetControls.tsx @@ -10,6 +10,7 @@ import { GridColDef, GridActionsCellItem, GridRowId } from '@mui/x-data-grid'; import DeleteIcon from '@mui/icons-material/DeleteOutlined'; import { useConfirmation } from '../../context/Confirmation.context'; import { useDeleteEntryMutation } from '../../graphql/entry/entry'; +import { useTranslation } from 'react-i18next'; export const DatasetControls: React.FC = () => { const [add, setAdd] = useState(false); @@ -17,6 +18,7 @@ export const DatasetControls: React.FC = () => { const [datasets, setDatasets] = useState([]); const [getDatasets, getDatasetsResults] = useGetDatasetsLazyQuery(); const [deleteEntryMutation] = useDeleteEntryMutation(); + const { t } = useTranslation(); const confirmation = useConfirmation(); @@ -52,8 +54,8 @@ export const DatasetControls: React.FC = () => { const handleDelete = async (id: GridRowId) => { // Execute delete mutation confirmation.pushConfirmationRequest({ - title: 'Delete Entry', - message: 'Are you sure you want to delete this project? Doing so will delete all associated tags', + title: t('components.datasetControl.deleteEntry'), + message: t('components.datasetControl.deleteDescription'), onConfirm: async () => { const res = await deleteEntryMutation({ variables: { entry: id.toString() } }); if (res.errors) { @@ -71,7 +73,7 @@ export const DatasetControls: React.FC = () => { { field: 'delete', type: 'actions', - headerName: 'Delete', + headerName: t('common.delete'), width: 120, maxWidth: 120, cellClassName: 'delete', @@ -79,7 +81,7 @@ export const DatasetControls: React.FC = () => { return [ } - label="Delete" + label={t('common.delete')} onClick={() => handleDelete(params.id)} /> ]; @@ -89,7 +91,7 @@ export const DatasetControls: React.FC = () => { return ( <> - Dataset Controls + {t('menu.datasetControl')} { - Add New Dataset + {t('components.datasetControl.addDataset')} { - Upload Entries + {t('components.datasetControl.uploadEntries')} diff --git a/packages/client/src/pages/datasets/ProjectAccess.tsx b/packages/client/src/pages/datasets/ProjectAccess.tsx index 9fb082c8..c0fc8a48 100644 --- a/packages/client/src/pages/datasets/ProjectAccess.tsx +++ b/packages/client/src/pages/datasets/ProjectAccess.tsx @@ -5,12 +5,14 @@ import { useGetDatasetProjectPermissionsLazyQuery } from '../../graphql/permissi import { useEffect, useState } from 'react'; import { DatasetProjectPermission, Project } from '../../graphql/graphql'; import { useGrantProjectDatasetAccessMutation } from '../../graphql/permission/permission'; +import { useTranslation } from 'react-i18next'; export const ProjectAccess: React.FC = () => { const { project } = useProject(); const [getDatasetProjectPermissions, datasetProjectPermissionResults] = useGetDatasetProjectPermissionsLazyQuery(); const [projectAccess, setProjectAccess] = useState([]); const [grantProjectDatasetAccess, grantProjectDatasetAccessResults] = useGrantProjectDatasetAccessMutation(); + const { t } = useTranslation(); // For querying for the permissions useEffect(() => { @@ -38,16 +40,21 @@ export const ProjectAccess: React.FC = () => { }; const columns: GridColDef[] = [ - { field: 'name', headerName: 'Dataset Name', width: 200, valueGetter: (params) => params.row.dataset.name }, + { + field: 'name', + headerName: t('components.projectAccess.datasetName'), + width: 200, + valueGetter: (params) => params.row.dataset.name + }, { field: 'description', - headerName: 'Description', + headerName: t('common.description'), width: 200, valueGetter: (params) => params.row.dataset.description }, { field: 'access', - headerName: 'Project Has Access', + headerName: t('components.projectAccess.projectHasAccess'), width: 200, renderCell: (params) => ( @@ -59,11 +66,13 @@ export const ProjectAccess: React.FC = () => { <> {project ? ( <> - Dataset Access for "{project.name}" + + {t('components.projectAccess.accessFor')}"{project.name}" + row.dataset._id} /> ) : ( - Select a Project to Continue + {t('components.projectAccess.selectProject')} )} ); diff --git a/packages/client/src/pages/projects/NewProject.tsx b/packages/client/src/pages/projects/NewProject.tsx index 62d822ea..abe14f94 100644 --- a/packages/client/src/pages/projects/NewProject.tsx +++ b/packages/client/src/pages/projects/NewProject.tsx @@ -66,7 +66,7 @@ export const NewProject: React.FC = () => { { instancePath: '/name', keyword: 'uniqueProjectName', - message: 'A project with this name already exists', + message: t('components.newProject.projectExists'), schemaPath: '#/properties/name/name', params: { keyword: 'uniqueProjectName' } } @@ -116,7 +116,7 @@ export const NewProject: React.FC = () => { additionalErrors={additionalErrors} /> ); diff --git a/packages/client/src/pages/projects/ProjectControl.tsx b/packages/client/src/pages/projects/ProjectControl.tsx index 62471768..894a84b2 100644 --- a/packages/client/src/pages/projects/ProjectControl.tsx +++ b/packages/client/src/pages/projects/ProjectControl.tsx @@ -7,18 +7,20 @@ import { Project } from '../../graphql/graphql'; import { useDeleteProjectMutation } from '../../graphql/project/project'; import { useConfirmation } from '../../context/Confirmation.context'; import { useEffect } from 'react'; +import { useTranslation } from 'react-i18next'; const ProjectControl: React.FC = () => { const { projects, updateProjectList } = useProject(); const [deleteProjectMutation, deleteProjectResults] = useDeleteProjectMutation(); const confirmation = useConfirmation(); + const { t } = useTranslation(); const handleDelete = async (id: GridRowId) => { // Execute delete mutation confirmation.pushConfirmationRequest({ - title: 'Delete Study', - message: 'Are you sure you want to delete this project? Doing so will delete all contained studies and tags', + title: t('components.projectControl.deleteStudy'), + message: t('components.projectControl.deleteDescription'), onConfirm: () => { deleteProjectMutation({ variables: { project: id.toString() } }); }, @@ -36,32 +38,38 @@ const ProjectControl: React.FC = () => { const columns: GridColDef[] = [ { field: 'name', - headerName: 'Name', + headerName: t('common.name'), width: 200, editable: false }, { field: 'description', - headerName: 'Description', + headerName: t('common.description'), width: 500, editable: false }, { field: 'delete', type: 'actions', - headerName: 'Delete', + headerName: t('common.delete'), width: 120, maxWidth: 120, cellClassName: 'delete', getActions: (params) => { - return [} label="Delete" onClick={() => handleDelete(params.id)} />]; + return [ + } + label={t('common.delete')} + onClick={() => handleDelete(params.id)} + /> + ]; } } ]; return ( <> - Project Control + {t('menu.projectControl')} row._id} /> diff --git a/packages/client/src/pages/projects/ProjectUserPermissions.tsx b/packages/client/src/pages/projects/ProjectUserPermissions.tsx index 4d3a9674..7d649fd4 100644 --- a/packages/client/src/pages/projects/ProjectUserPermissions.tsx +++ b/packages/client/src/pages/projects/ProjectUserPermissions.tsx @@ -6,13 +6,15 @@ import { ProjectPermissionModel, Project } from '../../graphql/graphql'; import { useGetProjectPermissionsQuery } from '../../graphql/permission/permission'; import { DecodedToken, useAuth } from '../../context/Auth.context'; import { useGrantProjectPermissionsMutation } from '../../graphql/permission/permission'; +import { useTranslation } from 'react-i18next'; export const ProjectUserPermissions: React.FC = () => { const { project } = useProject(); + const { t } = useTranslation(); return ( <> - User Permissions + {t('menu.userPermissions')} {project && } ); @@ -62,6 +64,7 @@ const UserPermissionTable: React.FC<{ project: Project }> = ({ project }) => { const [rows, setRows] = useState([]); const { decodedToken } = useAuth(); + const { t } = useTranslation(); useEffect(() => { if (data?.getProjectPermissions) { @@ -88,7 +91,7 @@ const UserPermissionTable: React.FC<{ project: Project }> = ({ project }) => { */ { field: 'email', - headerName: 'Email', + headerName: t('common.email'), valueGetter: (params) => params.row.user.email, flex: 1.75, editable: false @@ -96,7 +99,7 @@ const UserPermissionTable: React.FC<{ project: Project }> = ({ project }) => { { field: 'projectAdmin', type: 'boolean', - headerName: 'Project Admin', + headerName: t('components.projectUserPermissions.projectAdmin'), valueGetter: (params) => params.row.hasRole, renderCell: (params: GridRenderCellParams) => { return ( diff --git a/packages/client/src/pages/studies/DownloadTags.tsx b/packages/client/src/pages/studies/DownloadTags.tsx index 6b32995d..c3ff29dd 100644 --- a/packages/client/src/pages/studies/DownloadTags.tsx +++ b/packages/client/src/pages/studies/DownloadTags.tsx @@ -1,11 +1,14 @@ import { Button, Container, Typography } from '@mui/material'; +import { useTranslation } from 'react-i18next'; export const DownloadTags: React.FC = () => { + const { t } = useTranslation(); + return ( - Download Tags + {t('menu.downloadTags')} ); diff --git a/packages/client/src/pages/studies/EntryControls.tsx b/packages/client/src/pages/studies/EntryControls.tsx index f99688f4..428238c7 100644 --- a/packages/client/src/pages/studies/EntryControls.tsx +++ b/packages/client/src/pages/studies/EntryControls.tsx @@ -6,6 +6,7 @@ import { DatasetsView } from '../../components/DatasetsView.component'; import { useGetDatasetsByProjectQuery } from '../../graphql/dataset/dataset'; import { useProject } from '../../context/Project.context'; import ToggleEntryEnabled from '../../components/ToggleEntryEnabled.component'; +import { useTranslation } from 'react-i18next'; export const EntryControls: React.FC = () => { const { project } = useProject(); @@ -15,6 +16,7 @@ export const EntryControls: React.FC = () => { project: project ? project._id : '' } }); + const { t } = useTranslation(); useEffect(() => { if (getDatasetsByProjectResults.data) { @@ -26,7 +28,7 @@ export const EntryControls: React.FC = () => { { field: 'enabled', type: 'actions', - headerName: 'Enable', + headerName: t('common.enable'), width: 120, maxWidth: 120, cellClassName: 'enabled', @@ -38,7 +40,7 @@ export const EntryControls: React.FC = () => { return ( <> - Entry Control + {t('menu.entryControl')} ); diff --git a/packages/client/src/pages/studies/NewStudy.tsx b/packages/client/src/pages/studies/NewStudy.tsx index 44bf3f77..8e269e54 100644 --- a/packages/client/src/pages/studies/NewStudy.tsx +++ b/packages/client/src/pages/studies/NewStudy.tsx @@ -10,6 +10,7 @@ import { useProject } from '../../context/Project.context'; import { useStudy } from '../../context/Study.context'; import { useApolloClient } from '@apollo/client'; import { CreateTagsDocument } from '../../graphql/tag/tag'; +import { useTranslation } from 'react-i18next'; export const NewStudy: React.FC = () => { const [activeStep, setActiveStep] = useState(0); @@ -21,6 +22,7 @@ export const NewStudy: React.FC = () => { const [_trainingSet, setTrainingSet] = useState([]); const [taggingSet, setTaggingSet] = useState([]); const apolloClient = useApolloClient(); + const { t } = useTranslation(); // Handles mantaining which step the user is on and the step limit useEffect(() => { @@ -109,22 +111,22 @@ export const NewStudy: React.FC = () => { return ( <> - Create New Study + {t('components.newStudy.createStudy')} {steps.map((label) => { return ( - {label} + {t('components.newStudy.steps.' + label)} ); })} {activeStep === steps.length ? ( <> - All steps completed - your new study is created + {t('components.newStudy.completed')} - + ) : ( @@ -132,10 +134,10 @@ export const NewStudy: React.FC = () => { {getSectionComponent()} diff --git a/packages/client/src/pages/studies/StudyControl.tsx b/packages/client/src/pages/studies/StudyControl.tsx index 96e6ab08..bda2db98 100644 --- a/packages/client/src/pages/studies/StudyControl.tsx +++ b/packages/client/src/pages/studies/StudyControl.tsx @@ -7,18 +7,20 @@ import { Study } from '../../graphql/graphql'; import { useDeleteStudyMutation } from '../../graphql/study/study'; import { useEffect } from 'react'; import { useConfirmation } from '../../context/Confirmation.context'; +import { useTranslation } from 'react-i18next'; export const StudyControl: React.FC = () => { const { studies, updateStudies } = useStudy(); const [deleteStudyMutation, deleteStudyResults] = useDeleteStudyMutation(); const confirmation = useConfirmation(); + const { t } = useTranslation(); const handleDelete = async (id: GridRowId) => { // Execute delete mutation confirmation.pushConfirmationRequest({ - title: 'Delete Study', - message: 'Are you sure you want to delete this study? Doing so will delete all contained tags', + title: t('components.studyControl.deleteStudy'), + message: t('components.studyControl.deleteDescription'), onConfirm: () => { deleteStudyMutation({ variables: { study: id.toString() } }); }, @@ -36,32 +38,38 @@ export const StudyControl: React.FC = () => { const columns: GridColDef[] = [ { field: 'name', - headerName: 'Name', + headerName: t('common.name'), width: 200, editable: false }, { field: 'description', - headerName: 'Description', + headerName: t('common.description'), width: 500, editable: false }, { field: 'delete', type: 'actions', - headerName: 'Delete', + headerName: t('common.delete'), width: 120, maxWidth: 120, cellClassName: 'delete', getActions: (params) => { - return [} label="Delete" onClick={() => handleDelete(params.id)} />]; + return [ + } + label={t('common.delete')} + onClick={() => handleDelete(params.id)} + /> + ]; } } ]; return ( <> - Study Control + {t('menu.studyControl')} row._id} /> diff --git a/packages/client/src/pages/studies/UserPermissions.tsx b/packages/client/src/pages/studies/UserPermissions.tsx index f752d4cc..3bdc59cf 100644 --- a/packages/client/src/pages/studies/UserPermissions.tsx +++ b/packages/client/src/pages/studies/UserPermissions.tsx @@ -10,13 +10,15 @@ import { useGrantTrainedContributorMutation } from '../../graphql/permission/permission'; import { useEffect, useState } from 'react'; +import { useTranslation } from 'react-i18next'; export const StudyUserPermissions: React.FC = () => { const { study } = useStudy(); + const { t } = useTranslation(); return ( <> - User Permissions + {t('menu.userPermissions')} {study && } ); @@ -122,6 +124,7 @@ const UserPermissionTable: React.FC<{ study: Study }> = ({ study }) => { }); const [permissions, setPermissions] = useState([]); + const { t } = useTranslation(); useEffect(() => { if (data) { @@ -132,7 +135,7 @@ const UserPermissionTable: React.FC<{ study: Study }> = ({ study }) => { const columns: GridColDef[] = [ { field: 'email', - headerName: 'Email', + headerName: t('common.email'), valueGetter: (params) => params.row.user.email, flex: 1.75, editable: false @@ -140,7 +143,7 @@ const UserPermissionTable: React.FC<{ study: Study }> = ({ study }) => { { field: 'studyAdmin', type: 'boolean', - headerName: 'Study Admin', + headerName: t('components.userPermissions.studyAdmin'), valueGetter: (params) => params.row.isStudyAdmin, renderCell: (params: GridRenderCellParams) => { return ( @@ -152,7 +155,7 @@ const UserPermissionTable: React.FC<{ study: Study }> = ({ study }) => { }, { field: 'contributor', - headerName: 'Contributor', + headerName: t('components.userPermissions.contributor'), valueGetter: (params) => params.row.isContributor, renderCell: (params: GridRenderCellParams) => { return ( @@ -164,7 +167,7 @@ const UserPermissionTable: React.FC<{ study: Study }> = ({ study }) => { }, { field: 'trained', - headerName: 'Trained', + headerName: t('components.userPermissions.trained'), valueGetter: (params) => params.row.isTrained, renderCell: (params: GridRenderCellParams) => { return (