diff --git a/Makefile b/Makefile
index 762b4ea5c29..233c1df56b7 100755
--- a/Makefile
+++ b/Makefile
@@ -79,6 +79,8 @@ locales:
msgfmt -o modules/api_docs/locale/ja/LC_MESSAGES/api_docs.mo modules/api_docs/locale/ja/LC_MESSAGES/api_docs.po
msgfmt -o modules/battery_manager/locale/ja/LC_MESSAGES/battery_manager.mo modules/battery_manager/locale/ja/LC_MESSAGES/battery_manager.po
msgfmt -o modules/behavioural_qc/locale/ja/LC_MESSAGES/behavioural_qc.mo modules/behavioural_qc/locale/ja/LC_MESSAGES/behavioural_qc.po
+ msgfmt -o modules/behavioural_qc/locale/hi/LC_MESSAGES/behavioural_qc.mo modules/behavioural_qc/locale/hi/LC_MESSAGES/behavioural_qc.po
+ npx i18next-conv -l hi -s modules/behavioural_qc/locale/hi/LC_MESSAGES/behavioural_qc.po -t modules/behavioural_qc/locale/hi/LC_MESSAGES/behavioural_qc.json
msgfmt -o modules/brainbrowser/locale/ja/LC_MESSAGES/brainbrowser.mo modules/brainbrowser/locale/ja/LC_MESSAGES/brainbrowser.po
msgfmt -o modules/bvl_feedback/locale/ja/LC_MESSAGES/bvl_feedback.mo modules/bvl_feedback/locale/ja/LC_MESSAGES/bvl_feedback.po
msgfmt -o modules/candidate_list/locale/ja/LC_MESSAGES/candidate_list.mo modules/candidate_list/locale/ja/LC_MESSAGES/candidate_list.po
@@ -192,3 +194,8 @@ server_processes_manager: modules/server_processes_manager/locale/ja/LC_MESSAGES
conflict_resolver:
target=conflict_resolver npm run compile
+
+behavioural_qc:
+ msgfmt -o modules/behavioural_qc/locale/hi/LC_MESSAGES/behavioural_qc.mo modules/behavioural_qc/locale/hi/LC_MESSAGES/behavioural_qc.po
+ npx i18next-conv -l hi -s modules/behavioural_qc/locale/hi/LC_MESSAGES/behavioural_qc.po -t modules/behavioural_qc/locale/hi/LC_MESSAGES/behavioural_qc.json
+ target=behavioural_qc npm run compile
\ No newline at end of file
diff --git a/locale/hi/LC_MESSAGES/loris.po b/locale/hi/LC_MESSAGES/loris.po
index 337fc38afde..4709e9f217a 100644
--- a/locale/hi/LC_MESSAGES/loris.po
+++ b/locale/hi/LC_MESSAGES/loris.po
@@ -130,6 +130,12 @@ msgstr "रद्द करें"
msgid "Success!"
msgstr "सफलता!"
+msgid "Selection Filter"
+msgstr "चयन फ़िल्टर"
+
+msgid "Clear Filters"
+msgstr "फ़िल्टर साफ़ करें"
+
# Common candidate terms
msgid "PSCID"
msgstr "पीएससीआईडी"
@@ -146,6 +152,9 @@ msgstr "साइट"
msgid "Module"
msgstr "मॉड्यूल"
+msgid "Instrument"
+msgstr "उपकरण"
+
msgid "Project"
msgstr "परियोजना"
diff --git a/locale/loris.pot b/locale/loris.pot
index a1456967b2c..ca463f31ed6 100644
--- a/locale/loris.pot
+++ b/locale/loris.pot
@@ -132,6 +132,12 @@ msgstr ""
msgid "Success!"
msgstr ""
+msgid "Selection Filters"
+msgstr ""
+
+msgid "Clear Filters"
+msgstr ""
+
# Common candidate terms
msgid "PSCID"
msgstr ""
@@ -148,6 +154,9 @@ msgstr ""
msgid "Module"
msgstr ""
+msgid "Instrument"
+msgstr ""
+
msgid "Project"
msgstr ""
diff --git a/modules/behavioural_qc/jsx/behaviouralQCIndex.js b/modules/behavioural_qc/jsx/behaviouralQCIndex.js
index c62bd7f2ef9..33c01860af2 100644
--- a/modules/behavioural_qc/jsx/behaviouralQCIndex.js
+++ b/modules/behavioural_qc/jsx/behaviouralQCIndex.js
@@ -10,6 +10,7 @@ import IncompleteForms from './tabs_content/incompleteForms';
import DataConflicts from './tabs_content/dataConflicts';
import BehaviouralFeedback from './tabs_content/behaviouralFeedback';
+import hiStrings from '../locale/hi/LC_MESSAGES/behavioural_qc.json';
/**
* Behavioural Quality Control.
*
@@ -20,10 +21,14 @@ import BehaviouralFeedback from './tabs_content/behaviouralFeedback';
* @version 1.0.0
*/
const BehaviouralQC = (props) => {
+ const {t} = props;
const tabList = [
- {id: 'tabIncompleteForms', label: 'Incomplete Forms'},
- {id: 'tabDataConflicts', label: 'Data Conflicts'},
- {id: 'tabBehaviouralFeedback', label: 'Behavioural Feedback'},
+ {id: 'tabIncompleteForms', label: t('Incomplete Forms',
+ {ns: 'behavioural_qc'})},
+ {id: 'tabDataConflicts', label: t('Data Conflicts',
+ {ns: 'behavioural_qc'})},
+ {id: 'tabBehaviouralFeedback', label: t('Behavioural Feedback',
+ {ns: 'behavioural_qc'})},
];
/**
@@ -49,6 +54,7 @@ const BehaviouralQC = (props) => {
};
BehaviouralQC.propTypes = {
baseURL: PropTypes.string.isRequired,
+ t: PropTypes.func, // ADD THIS
};
/**
@@ -56,6 +62,7 @@ BehaviouralQC.propTypes = {
*/
window.addEventListener('load', () => {
i18n.addResourceBundle('ja', 'behavioural_qc', {});
+ i18n.addResourceBundle('hi', 'behavioural_qc', hiStrings);
const Index = withTranslation(
['behavioural_qc', 'loris']
)(BehaviouralQC);
diff --git a/modules/behavioural_qc/jsx/tabs_content/behaviouralFeedback.js b/modules/behavioural_qc/jsx/tabs_content/behaviouralFeedback.js
index 3d7fba2661a..05afc1b9c76 100644
--- a/modules/behavioural_qc/jsx/tabs_content/behaviouralFeedback.js
+++ b/modules/behavioural_qc/jsx/tabs_content/behaviouralFeedback.js
@@ -2,6 +2,7 @@ import React, {Component} from 'react';
import PropTypes from 'prop-types';
import Loader from 'jsx/Loader';
import FilterableDataTable from 'jsx/FilterableDataTable';
+import {withTranslation} from 'react-i18next';
/**
* Behavioural Feedback Component.
@@ -80,83 +81,75 @@ class BehaviouralFeedback extends Component {
* @return {*} a formatted table cell for a given column
*/
formatColumn(column, cell, rowData, rowHeaders) {
- let reactElement;
- switch (column) {
- case 'PSCID':
- reactElement = (
+ const {t} = this.props;
+ const labelPSCID = t('PSCID', {ns: 'loris'});
+ const labelDCCID = t('DCCID', {ns: 'loris'});
+ const labelBVL = t('Feedback Level', {ns: 'behavioural_qc'});
+
+ // PSCID column (match English or translated)
+ if (column === 'PSCID' || column === labelPSCID) {
+ return (
-
+
{rowData['PSCID']}
|
);
- break;
- case 'DCCID':
- reactElement = (
+ }
+
+ // DCCID column
+ if (column === 'DCCID' || column === labelDCCID) {
+ return (
-
+
{rowData['DCCID']}
|
);
- break;
- case 'Feedback Level':
+ }
+
+ // Feedback Level column — build link depending on row data
+ if (column === 'Feedback Level' || column === labelBVL) {
let bvlLink = '';
let bvlLevel = '';
if (rowData['Instrument']) {
bvlLink = this.props.baseURL +
- '/instruments/' +
- rowData['Test Name'] +
- '/?candID=' +
- rowData['DCCID'] +
- '&sessionID=' +
- rowData['sessionID'] +
- '&commentID=' +
- rowData['commentID'];
- // Open feedback panel
- bvlLink += '&showFeedback=true';
- bvlLevel ='Instrument : ' + rowData['Instrument'];
+ '/instruments/' +
+ rowData['Test Name'] +
+ '/?candID=' + rowData['DCCID'] +
+ '&sessionID=' + rowData['sessionID'] +
+ '&commentID=' + rowData['commentID'] +
+ '&showFeedback=true';
+ bvlLevel = t('Instrument', {ns: 'behavioural_qc'}) + ' : '
+ + rowData['Instrument'];
} else if (rowData['Visit']) {
bvlLink = this.props.baseURL +
- '/instrument_list/' +
- '?candID=' +
- rowData['DCCID'] +
- '&sessionID=' +
- rowData['sessionID'];
- // Open feedback panel
- bvlLink += '&showFeedback=true';
- bvlLevel ='Visit : ' + rowData['Visit'];
+ '/instrument_list/?candID=' + rowData['DCCID'] +
+ '&sessionID=' + rowData['sessionID'] +
+ '&showFeedback=true';
+ bvlLevel = t('Visit', {ns: 'behavioural_qc'}) + ' : '
+ + rowData['Visit'];
} else {
- bvlLink = this.props.baseURL +
- '/' + rowData['DCCID'];
- // Open feedback panel
- bvlLink += '/?showFeedback=true';
- bvlLevel ='Profile : ' + rowData['PSCID'];
+ bvlLink = this.props.baseURL + '/' + rowData['DCCID']
+ + '/?showFeedback=true';
+ bvlLevel = t('Profile', {ns: 'behavioural_qc'}) + ' : '
+ + rowData['PSCID'];
}
- reactElement = (
+ return (
{bvlLevel}
|
);
- break;
- default:
- reactElement = (
- {cell} |
- );
}
- return reactElement;
+
+ return {cell} | ;
}
/**
* @return {JSX} the feedback form to render.
*/
render() {
+ const {t} = this.props;
// Waiting for async data to load.
if (!this.state.isLoaded) {
return ;
@@ -167,7 +160,7 @@ class BehaviouralFeedback extends Component {
// The fields configured for display/hide.
let fields = [
{
- label: 'Instrument',
+ label: t('Instrument', {ns: 'loris'}),
show: false,
filter: {
name: 'Instrument',
@@ -179,7 +172,7 @@ class BehaviouralFeedback extends Component {
},
},
{
- label: 'DCCID',
+ label: t('DCCID', {ns: 'loris'}),
show: true,
filter: {
name: 'DCCID',
@@ -187,7 +180,7 @@ class BehaviouralFeedback extends Component {
},
},
{
- label: 'PSCID',
+ label: t('PSCID', {ns: 'loris'}),
show: true,
filter: {
name: 'PSCID',
@@ -195,7 +188,7 @@ class BehaviouralFeedback extends Component {
},
},
{
- label: 'Visit',
+ label: t('Visit', {ns: 'loris'}),
show: false,
filter: {
name: 'Visit',
@@ -204,7 +197,7 @@ class BehaviouralFeedback extends Component {
},
},
{
- label: 'Project',
+ label: t('Project', {ns: 'loris'}),
show: false,
filter: {
name: 'Project',
@@ -213,7 +206,7 @@ class BehaviouralFeedback extends Component {
},
},
{
- label: 'Cohort',
+ label: t('Cohort', {ns: 'loris'}),
show: false,
filter: {
name: 'Cohort',
@@ -222,7 +215,7 @@ class BehaviouralFeedback extends Component {
},
},
{
- label: 'Site',
+ label: t('Site', {ns: 'loris'}),
show: false,
filter: {
name: 'Site',
@@ -243,19 +236,19 @@ class BehaviouralFeedback extends Component {
show: false,
},
{
- label: 'Feedback Level',
+ label: t('Feedback Level', {ns: 'behavioural_qc'}),
show: true,
},
{
- label: 'Test Name',
+ label: t('Test Name', {ns: 'behavioural_qc'}),
show: false,
},
{
- label: 'Field Name',
+ label: t('Field Name', {ns: 'behavioural_qc'}),
show: false,
},
{
- label: 'Feedback Status',
+ label: t('Feedback Status', {ns: 'behavioural_qc'}),
show: true,
},
];
@@ -280,6 +273,8 @@ BehaviouralFeedback.propTypes = {
display: PropTypes.bool,
data: PropTypes.object,
baseURL: PropTypes.string.isRequired,
+ t: PropTypes.func,
};
-export default BehaviouralFeedback;
+export default withTranslation(
+ ['behavioural_qc', 'loris'])(BehaviouralFeedback);
diff --git a/modules/behavioural_qc/jsx/tabs_content/dataConflicts.js b/modules/behavioural_qc/jsx/tabs_content/dataConflicts.js
index c2b4d061185..71a6e7f6d69 100644
--- a/modules/behavioural_qc/jsx/tabs_content/dataConflicts.js
+++ b/modules/behavioural_qc/jsx/tabs_content/dataConflicts.js
@@ -2,6 +2,7 @@ import React, {Component} from 'react';
import PropTypes from 'prop-types';
import Loader from 'jsx/Loader';
import FilterableDataTable from 'jsx/FilterableDataTable';
+import {withTranslation} from 'react-i18next';
/**
* Data Conflicts Component.
@@ -150,6 +151,7 @@ class DataConflicts extends Component {
* @return {JSX} the data conflicts form to render.
*/
render() {
+ const {t} = this.props;
// Waiting for async data to load.
if (!this.state.isLoaded) {
return ;
@@ -161,7 +163,7 @@ class DataConflicts extends Component {
// The fields configured for display/hide.
let fields = [
{
- label: 'Instrument',
+ label: t('Instrument', {ns: 'loris'}),
show: true,
filter: {
name: 'Instrument',
@@ -173,7 +175,7 @@ class DataConflicts extends Component {
},
},
{
- label: 'DCCID',
+ label: t('DCCID', {ns: 'loris'}),
show: true,
filter: {
name: 'DCCID',
@@ -181,7 +183,7 @@ class DataConflicts extends Component {
},
},
{
- label: 'PSCID',
+ label: t('PSCID', {ns: 'loris'}),
show: true,
filter: {
name: 'PSCID',
@@ -189,7 +191,7 @@ class DataConflicts extends Component {
},
},
{
- label: 'Visit',
+ label: t('Visit', {ns: 'loris'}),
show: true,
filter: {
name: 'Visit',
@@ -198,7 +200,7 @@ class DataConflicts extends Component {
},
},
{
- label: 'Project',
+ label: t('Project', {ns: 'loris'}),
show: false,
filter: {
name: 'Project',
@@ -207,7 +209,7 @@ class DataConflicts extends Component {
},
},
{
- label: 'Cohort',
+ label: t('Cohort', {ns: 'loris'}),
show: false,
filter: {
name: 'Cohort',
@@ -216,7 +218,7 @@ class DataConflicts extends Component {
},
},
{
- label: 'Site',
+ label: t('Site', {ns: 'loris'}),
show: false,
filter: {
name: 'Site',
@@ -225,7 +227,7 @@ class DataConflicts extends Component {
},
},
{
- label: 'Field Name',
+ label: t('Field Name', {ns: 'behavioural_qc'}),
show: true,
},
{
@@ -266,6 +268,7 @@ DataConflicts.propTypes = {
display: PropTypes.bool,
data: PropTypes.object,
baseURL: PropTypes.string.isRequired,
+ t: PropTypes.func,
};
-export default DataConflicts;
+export default withTranslation(['behavioural_qc', 'loris'])(DataConflicts);
diff --git a/modules/behavioural_qc/jsx/tabs_content/incompleteForms.js b/modules/behavioural_qc/jsx/tabs_content/incompleteForms.js
index 0fdcbd7b7b0..02ace97f698 100644
--- a/modules/behavioural_qc/jsx/tabs_content/incompleteForms.js
+++ b/modules/behavioural_qc/jsx/tabs_content/incompleteForms.js
@@ -2,6 +2,7 @@ import React, {Component} from 'react';
import PropTypes from 'prop-types';
import Loader from 'jsx/Loader';
import FilterableDataTable from 'jsx/FilterableDataTable';
+import {withTranslation} from 'react-i18next';
/**
* Incomplete Forms Component.
@@ -150,6 +151,7 @@ class IncompleteForms extends Component {
* @return {JSX} the incomplete form to render.
*/
render() {
+ const {t} = this.props;
// Waiting for async data to load.
if (!this.state.isLoaded) {
return ;
@@ -161,7 +163,7 @@ class IncompleteForms extends Component {
// The fields configured for display/hide.
let fields = [
{
- label: 'Instrument',
+ label: t('Instrument', {ns: 'loris'}),
show: true,
filter: {
name: 'Instrument',
@@ -173,19 +175,19 @@ class IncompleteForms extends Component {
},
},
{
- label: 'Data Entry Type',
+ label: t('Data Entry Type', {ns: 'behavioural_qc'}),
show: true,
filter: {
name: 'Data Entry Type',
type: 'select',
options: {
- 'IDE': 'Initial Data Entry (IDE)',
- 'DDE': 'Double Data Entry (DDE)',
+ 'IDE': t('Initial Data Entry (IDE)', {ns: 'behavioural_qc'}),
+ 'DDE': t('Double Data Entry (DDE)', {ns: 'behavioural_qc'}),
},
},
},
{
- label: 'DCCID',
+ label: t('DCCID', {ns: 'loris'}),
show: true,
filter: {
name: 'DCCID',
@@ -193,7 +195,7 @@ class IncompleteForms extends Component {
},
},
{
- label: 'PSCID',
+ label: t('PSCID', {ns: 'loris'}),
show: true,
filter: {
name: 'PSCID',
@@ -201,7 +203,7 @@ class IncompleteForms extends Component {
},
},
{
- label: 'Visit',
+ label: t('Visit', {ns: 'loris'}),
show: true,
filter: {
name: 'Visit',
@@ -210,7 +212,7 @@ class IncompleteForms extends Component {
},
},
{
- label: 'Project',
+ label: t('Project', {ns: 'loris'}),
show: false,
filter: {
name: 'Project',
@@ -219,7 +221,7 @@ class IncompleteForms extends Component {
},
},
{
- label: 'Cohort',
+ label: t('Cohort', {ns: 'loris'}),
show: false,
filter: {
name: 'Cohort',
@@ -228,7 +230,7 @@ class IncompleteForms extends Component {
},
},
{
- label: 'Site',
+ label: t('Site', {ns: 'loris'}),
show: false,
filter: {
name: 'Site',
@@ -277,6 +279,7 @@ IncompleteForms.propTypes = {
display: PropTypes.bool,
data: PropTypes.object,
baseURL: PropTypes.string.isRequired,
+ t: PropTypes.func,
};
-export default IncompleteForms;
+export default withTranslation(['behavioural_qc', 'loris'])(IncompleteForms);
diff --git a/modules/behavioural_qc/locale/behavioural_qc.pot b/modules/behavioural_qc/locale/behavioural_qc.pot
index 411b5fff841..cc8ebbe4716 100644
--- a/modules/behavioural_qc/locale/behavioural_qc.pot
+++ b/modules/behavioural_qc/locale/behavioural_qc.pot
@@ -21,6 +21,33 @@ msgstr ""
msgid "Behavioural Quality Control"
msgstr ""
-msgid "Behavioural Session"
-msgid_plural "Behavioural Sessions"
-msgstr[0] ""
+msgid "Incomplete Forms"
+msgstr ""
+
+msgid "Data Conflicts"
+msgstr ""
+
+msgid "Behavioural Feedback"
+msgstr ""
+
+msgid "Data Entry Type"
+msgstr ""
+
+msgid "Initial Data Entry (IDE)"
+msgstr ""
+
+msgid "Double Data Entry (DDE)"
+msgstr ""
+
+msgid "Field Name"
+msgstr ""
+
+msgid "Feedback Level"
+msgstr ""
+
+msgid "Test Name"
+msgstr ""
+
+msgid "Feedback Status"
+msgstr ""
+
diff --git a/modules/behavioural_qc/locale/hi/LC_MESSAGES/behavioural_qc.json b/modules/behavioural_qc/locale/hi/LC_MESSAGES/behavioural_qc.json
new file mode 100644
index 00000000000..ee19250d212
--- /dev/null
+++ b/modules/behavioural_qc/locale/hi/LC_MESSAGES/behavioural_qc.json
@@ -0,0 +1,13 @@
+{
+ "Behavioural Quality Control": "व्यवहारिक गुणवत्ता नियंत्रण",
+ "Incomplete Forms": "अधूरी प्रपत्र",
+ "Data Conflicts": "डेटा संघर्ष",
+ "Behavioural Feedback": "व्यवहारिक प्रतिक्रिया",
+ "Data Entry Type": "डेटा प्रविष्टि प्रकार",
+ "Initial Data Entry (IDE)": "प्रारंभिक डेटा प्रविष्टि (IDE)",
+ "Double Data Entry (DDE)": "द्वि-डेटा प्रविष्टि (DDE)",
+ "Field Name": "फ़ील्ड नाम",
+ "Feedback Level": "प्रतिक्रिया स्तर",
+ "Test Name": "परीक्षण नाम",
+ "Feedback Status": "प्रतिक्रिया स्थिति"
+}
\ No newline at end of file
diff --git a/modules/behavioural_qc/locale/hi/LC_MESSAGES/behavioural_qc.po b/modules/behavioural_qc/locale/hi/LC_MESSAGES/behavioural_qc.po
new file mode 100644
index 00000000000..a7e7a1321db
--- /dev/null
+++ b/modules/behavioural_qc/locale/hi/LC_MESSAGES/behavioural_qc.po
@@ -0,0 +1,54 @@
+# Default LORIS strings to be translated (English).
+# Copy this to a language specific file and add translations to the
+# new file.
+# Copyright (C) 2025
+# This file is distributed under the same license as the LORIS package.
+# Dave MacFarlane , 2025.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: LORIS 27\n"
+"Report-Msgid-Bugs-To: https://github.com/aces/Loris/issues\n"
+"POT-Creation-Date: 2025-04-08 14:37-0400\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME \n"
+"Language-Team: LANGUAGE \n"
+"Language: hi\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+msgid "Behavioural Quality Control"
+msgstr "व्यवहारिक गुणवत्ता नियंत्रण"
+
+msgid "Incomplete Forms"
+msgstr "अधूरी प्रपत्र"
+
+msgid "Data Conflicts"
+msgstr "डेटा संघर्ष"
+
+msgid "Behavioural Feedback"
+msgstr "व्यवहारिक प्रतिक्रिया"
+
+msgid "Data Entry Type"
+msgstr "डेटा प्रविष्टि प्रकार"
+
+msgid "Initial Data Entry (IDE)"
+msgstr "प्रारंभिक डेटा प्रविष्टि (IDE)"
+
+msgid "Double Data Entry (DDE)"
+msgstr "द्वि-डेटा प्रविष्टि (DDE)"
+
+msgid "Field Name"
+msgstr "फ़ील्ड नाम"
+
+msgid "Feedback Level"
+msgstr "प्रतिक्रिया स्तर"
+
+msgid "Test Name"
+msgstr "परीक्षण नाम"
+
+msgid "Feedback Status"
+msgstr "प्रतिक्रिया स्थिति"
+
+