Skip to content

[instruments] Multilingual instrument support #9522

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 20 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions SQL/0000-00-00-schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,18 @@ CREATE TABLE `test_names` (
CONSTRAINT `FK_test_names_1` FOREIGN KEY (`Sub_group`) REFERENCES `test_subgroups` (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `test_names_multilingual` (
`ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`Test_name` varchar(255) NOT NULL,
`Full_name` varchar(255) NOT NULL,
`LanguageID` int(10) unsigned NOT NULL,
PRIMARY KEY (`ID`),
KEY `FK_test_names_multilingual_1` (`Test_name`),
CONSTRAINT `FK_test_names_multilingual_1` FOREIGN KEY (`Test_name`) REFERENCES `test_names` (`Test_name`),
KEY `FK_test_names_multilingual_2` (`LanguageID`),
CONSTRAINT `FK_test_names_multilingual_2` FOREIGN KEY (`LanguageID`) REFERENCES `language` (`language_id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

CREATE TABLE `instrument_subtests` (
`ID` int(11) NOT NULL auto_increment,
`Test_name` varchar(255) NOT NULL default '',
Expand Down
13 changes: 13 additions & 0 deletions SQL/New_patches/2025-01-06-multilingual_test_names.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
CREATE TABLE `test_names_multilingual` (
`ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
`Test_name` varchar(255) NOT NULL,
`Full_name` varchar(255) NOT NULL,
`LanguageID` int(10) unsigned NOT NULL,
PRIMARY KEY (`ID`),
KEY `FK_test_names_multilingual_1` (`Test_name`),
CONSTRAINT `FK_test_names_multilingual_1` FOREIGN KEY (`Test_name`) REFERENCES `test_names` (`Test_name`),
KEY `FK_test_names_multilingual_2` (`LanguageID`),
CONSTRAINT `FK_test_names_multilingual_2` FOREIGN KEY (`LanguageID`) REFERENCES `language` (`language_id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

UPDATE session SET LanguageID='1' WHERE LanguageID IS NULL;
2 changes: 1 addition & 1 deletion modules/create_timepoint/test/create_timepointTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ function testDCCIDandProjectSite()
$this->_assertDropdownSelectedText('project', 'Pumpernickel');

// Check the "English" dropdown
$this->_assertDropdownSelectedText('languageID', 'English');
$this->_assertDropdownSelectedText('languageID', '');

// Check the "cohort" dropdown has "Fresh" and "Stale" as options
$this->_assertDropdownHasOptions('cohort', ['Fresh', 'Stale']);
Expand Down
5 changes: 5 additions & 0 deletions modules/instruments/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ determines which candidate age is displayed as part of the
metadata fields: `Candidate Age (Months)` or
`Candidate Age at Death (Months)`.

## Multi-lingual support
Instrument labels are added in JSON files with the language code as a key. A default JSON labels file is included in `modules/instruments/language_labels/instrument_library_labels.json` which includes English and French for labels referenced in NDB_BVL_Instruments.class.inc. To add more languages to be supported by a project's instruments, first add the language to the `language` table. Next, copy the `instrument_library_labels.json` file to `project/instruments/language_labels/instrument_library_labels.json` with a new key for the additional language, and all of the same labels translated into the additional language. This new file should be tracked on the project's repository.

Multilingual support is only available for PHP instrument at the moment. To have a multilingual instrument, the translated test name should be inserted into `test_names_multilingual` linked to the appropriate language ID. The function `$this->getLangLabel('key')` can be used anywhere in the instrument to display translated labels. A JSON file must be created in the same format as `modules/instruments/language_labels/instrument_library_labels.json` and put into the `project/instruments/language_labels/` directory with the following naming convention: <test_name>.json

## Interactions with LORIS

The survey module uses instruments of the same format as data entry
Expand Down
64 changes: 64 additions & 0 deletions modules/instruments/language_labels/instrument_library_labels.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
"en-CA" : {
"age_out_of_range" : " (Age out of range)",
"data_entry_error_detected" : "A data entry error has been detected so this data <b>WAS NOT SAVED</b>",
"age_not_found" : "Candidate age could not be found.",
"date_of_administration" : "Date of Administration",
"candidate_age" : "Candidate Age (Months)",
"candidate_age_death" : "Candidate Age at Death (Months)",
"window_difference" : "Window Difference (+/- Days)",
"examiner" : "Examiner",
"date_of_administration_required" : "Date of Administration is required",
"examiner_required" : "Examiner is required",
"required" : "Required.",
"field_required" : "This field is required.",
"yes" : "Yes",
"no" : "No",
"not_answered" : "Not Answered",
"specify_or_select" : "You must specify or select from the drop-down",
"88_refused" : "88 Refused",
"99_do_not_know" : "99 Do not know",
"select_status_leave_blank" : "You are required to select a status if you want to leave this time blank.",
"dnk" : "DNK",
"refusal" : "Refusal",
"date_or_NA_required" : "A Date, or Not Answered is required.",
"must_be_numeric" : "Value must be numeric.",
"must_be_greater_than" : "Must be greater than",
"must_be_less_than" : "Must be less than",
"is_required" : "is required.",
"window_difference_from_test_battery" : "Window difference from test battery (days)",
"top" : "Top",
"in_progress" : "In Progress",
"complete" : "Complete"
},
"fr-CA" : {
"age_out_of_range" : " (Âge hors limites)",
"data_entry_error_detected" : "Une erreur de saisie a été détectée, donc ces données <b>N'ONT PAS ÉTÉ ENREGISTRÉES</b>",
"age_not_found" : "L'âge du candidat n'a pas pu être trouvé.",
"date_of_administration" : "Date d'administration",
"candidate_age" : "Âge du candidat (en mois)",
"candidate_age_death" : "Âge du candidat au décès (en mois)",
"window_difference" : "Différence de fenêtre (+/- jours)",
"examiner" : "Examinateur",
"date_of_administration_required" : "La date d'administration est requise",
"examiner_required" : "L'examinateur est requis",
"required" : "Requis.",
"field_required" : "Ce champ est requis.",
"yes" : "Oui",
"no" : "Non",
"not_answered" : "Non répondu",
"specify_or_select" : "Vous devez spécifier ou sélectionner dans le menu déroulant",
"88_refused" : "88 Refusé",
"99_do_not_know" : "99 Ne sait pas",
"select_status_leave_blank" : "Vous devez sélectionner un statut si vous souhaitez laisser ce champ vide.",
"dnk" : "NSP",
"refusal" : "Refus",
"date_or_NA_required" : "Une date ou Non Répondu est requis.",
"must_be_numeric" : "La valeur doit être numérique.",
"must_be_greater_than" : "Doit être supérieur à",
"must_be_less_than" : "Doit être inférieur à",
"is_required" : "est requis.",
"window_difference_from_test_battery" : "Différence de fenêtre par rapport à la batterie de tests (jours)",
"top" : "Résumé"
}
}
8 changes: 6 additions & 2 deletions php/libraries/NDB_BVL_Battery.class.inc
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ class NDB_BVL_Battery

// craft the select query
$query = "SELECT t.Test_name,
t.Full_name,
COALESCE(tnm.Full_name, t.Full_name) AS Full_name,
f.CommentID,
CONCAT('DDE_', f.CommentID) AS DDECommentID,
ts.Subgroup_name as Sub_group,
Expand All @@ -347,14 +347,18 @@ class NDB_BVL_Battery
JOIN test_names t ON (f.TestID=t.ID)
JOIN test_subgroups ts ON (ts.ID = t.Sub_group)
LEFT JOIN session s ON (s.ID=f.SessionID)
LEFT JOIN test_names_multilingual tnm
ON tnm.LanguageID=s.LanguageID
LEFT JOIN test_battery b
ON ((t.Test_name=b.Test_name OR b.Test_name IS NULL)
AND (s.CohortID=b.CohortID OR b.CohortID IS NULL)
AND (s.Visit_label=b.Visit_label OR b.Visit_label IS NULL)
AND (s.CenterID=b.CenterID OR b.CenterID IS NULL))
WHERE f.SessionID=:SID
AND LEFT(f.CommentID, 4) != 'DDE_'
AND (tnm.Test_name=t.Test_name OR tnm.Test_name IS NULL)
GROUP BY t.Test_name,
tnm.Full_name,
t.Full_name,
f.CommentID,
DDECommentID,
Expand All @@ -366,7 +370,7 @@ class NDB_BVL_Battery
} else {
$query .= " ORDER BY Subgroup_order";
}
$query .= ", instrument_order, Full_name";
$query .= ", instrument_order, t.Full_name";
$qparams = ['SID' => $this->sessionID];

// get the list of instruments
Expand Down
Loading
Loading