diff --git a/Multilingual.php b/Multilingual.php index 6e0c212..41c839f 100644 --- a/Multilingual.php +++ b/Multilingual.php @@ -1,945 +1,932 @@ -getProjectSetting('use-api-endpoint', $project_id); - - // add multilingual_survey.js after making text replacements - $redcap_survey_javascript = file_get_contents($this->getModulePath() . 'js/multilingual_survey.js'); - $redcap_survey_javascript = str_replace('REDCAP_PDF_URL', ($this->getProjectSetting('multilingual-econsent', $project_id) ? $this->getUrl("multilingualPDF.php", true, ($api_endpoint == true ? true : false)) : 'false') . '&id=' . $record . '&form=' . $instrument . '&event_id=' . $event_id . '&instance=' . $repeat_instance, $redcap_survey_javascript); - $redcap_survey_javascript = str_replace('APP_PATH_IMAGES', APP_PATH_IMAGES, $redcap_survey_javascript); - $redcap_survey_javascript = str_replace('REDCAP_INSTRUMENT_NAME', $instrument, $redcap_survey_javascript); - $redcap_survey_javascript = str_replace('MULTILINGUAL_RECORD_ID', $record, $redcap_survey_javascript); - $redcap_survey_javascript = str_replace('REDCAP_LANGUAGE_VARIABLE', $this->languageVariable($project_id), $redcap_survey_javascript); - $redcap_survey_javascript = str_replace('REDCAP_AJAX_URL', $this->getUrl("index.php", true, ($api_endpoint == true ? true : false)), $redcap_survey_javascript); - $redcap_survey_javascript = str_replace('MULTILINGUAL_LANGUAGE_SELECTED_URL', $this->getUrl('languageSelected.php'), $redcap_survey_javascript); - $redcap_survey_javascript = str_replace('MULTILINGUAL_SURVEY_EVENT', $event_id, $redcap_survey_javascript); - - // see if pdf translation is configured or not -- set variable in multilingual_survey.js - if ($this->getProjectSetting("translate_pdfs_instruments")) { - $redcap_survey_javascript = str_replace('MULTILINGUAL_PDF_TRANSLATION_ENABLED', 'true', $redcap_survey_javascript); - } else { - $redcap_survey_javascript = str_replace('MULTILINGUAL_PDF_TRANSLATION_ENABLED', 'false', $redcap_survey_javascript); - } - - echo ""; - echo ''; - } - - function redcap_survey_complete($project_id, $record, $instrument, $event_id, $group_id = NULL, $survey_hash, $response_id = NULL, $repeat_instance){ - $api_endpoint = $this->getProjectSetting('use-api-endpoint', $project_id); - // Update and add multilingual_survey_complete - echo ''; - } - - function redcap_data_entry_form($project_id, $record, $instrument){ - echo ''; - echo ''; - } - - function redcap_pdf($project_id, $metadata, $data, $instrument, $record, $event_id, $instance) { - // delay execution of this module to allow multi-consent-signature module to do it's thing - if ($this->delayModuleExecution()) { - return; - } - - // get which languages were selected for which instruments by the user as they were taking surveys - $user_langs = $this->getUserSelectedLanguages($record); - - if (empty($user_langs)) { - // user never selected a lang, do no translations - return array('metadata'=>$metadata, 'data'=>$data); - } - - // log to project event table - $action_description = "Translating Generated PDF"; - $changes_made = "The Multilingual module will translate field labels (for each instrument) based on language selections the user made in survey(s)."; - \REDCap::logEvent($action_description, $changes_made, null, $record_id, $event_id); - - // translate metadata using user selected languages - global $Proj; - $translated_metadata = $this->translatePDF($metadata, $user_langs); - - return array('metadata'=>$translated_metadata, 'data'=>$data); - } - - function redcap_every_page_top($project_id){ - $api_endpoint = $this->getProjectSetting('use-api-endpoint', $project_id); - $at_survey_settings = strpos($_SERVER['REQUEST_URI'], 'Surveys/edit_info.php') !== false || strpos($_SERVER['REQUEST_URI'], 'Surveys/create_survey.php') !== false; - - //$user_rights = REDCap::getUserRights(); - //echo json_encode($user_rights); - - if(strpos($_SERVER['REQUEST_URI'], 'online_designer.php') !== false && isset($_GET['page'])){ - echo ''; - echo ''; - } - elseif(strpos($_SERVER['REQUEST_URI'], 'DataExport/index.php') !== false){ - echo ''; - } - elseif($_GET['__return'] == 1 or (isset($_GET['s']) && !isset($_GET['__page__']))){ - $instrument = $_GET['page']; - echo ''; - - echo ''; - } - elseif(strpos($_SERVER['REQUEST_URI'], 'DataEntry/index.php') !== false || strpos($_SERVER['REQUEST_URI'], 'DataEntry/record_home.php') !== false){ - echo ''; - echo ''; - } - elseif($at_survey_settings && isset($_GET['page'])){ - $index_url = $this->getUrl("index.php", true, ($api_endpoint == true ? true : false)); - $language_var = $this->languageVariable($project_id); - $stylesheet = ''; - $ml_survey_settings_js = ''; - $ml_survey_settings_js = str_replace('REDCAP_AJAX_URL', $index_url, $ml_survey_settings_js); - $ml_survey_settings_js = str_replace('REDCAP_LANGUAGE_VARIABLE', $language_var, $ml_survey_settings_js); - - echo $stylesheet; - echo $ml_survey_settings_js; - } - } - - /** - * @param $projectId - * @return string - */ - private function getMetaDataTableName($projectId){ - global $conn; - if($this->getProjectSetting('use-drafted-changes', $projectId)){ - $query = "select draft_mode from redcap_projects where project_id = " . mysqli_real_escape_string($conn, $data['project_id']); - if($result = mysqli_query($conn, $query)){ - if($row = mysqli_fetch_array($result)){ - $draftMode = $row["draft_mode"]; - return "redcap_metadata".($draftMode == 1?"_temp":""); - }else{ - error_log("Multilingual: no row to determine draft_mode"); - } - mysqli_free_result($result); - }else{ - error_log("Multilingual: no result to determine draft_mode"); - } - } - return "redcap_metadata"; - } - - public function languageVariable($project_id){ - $langVar = $this->getProjectSetting('languages_variable', $project_id); - if($langVar == ''){ - $langVar = 'languages'; - } - return $langVar; - } - - public function getSurveySettings($data) { - $instruments = $this->getProjectSetting('instruments'); - - if (!empty($instruments)) { - $instruments = json_decode($instruments); - $name = htmlspecialchars($data['instrument']); - $instrument = $instruments->$name; - } else { - $instruments = new \stdClass(); - } - - header('Content-Type: application/json'); - echo json_encode($instrument); - } - - public function saveSurveySettings($all_data) { - $instruments = $this->getProjectSetting('instruments'); - if (empty($instruments)) { - $instruments = new \stdClass(); - } else { - $instruments = json_decode($instruments); - } - - foreach ($all_data as $data) { - $instrument = htmlspecialchars($data['instrument']); - $lang = htmlspecialchars($data['language']); - if (empty($instruments->$instrument)) { - $instruments->$instrument = new \stdClass(); - } - if (empty($instruments->$instrument->$lang)) { - $instruments->$instrument->$lang = new \stdClass(); - } - foreach ($data['collections'] as $coll_name => $coll) { - $instruments->$instrument->$lang->$coll_name = new \stdClass(); - - // add each setting to collection after encoding HTML - foreach ($coll as $sname => $setting) { - $instruments->$instrument->$lang->$coll_name->$sname = htmlspecialchars($setting); - } - } - } - - $this->setProjectSetting('instruments', json_encode($instruments)); - } - - public function getSettings($data){ - $response = $this->getProjectSettings($data['project_id']); - - foreach($response AS $key => $values){ - if($key == 'button-width'){ - if(substr($response[$key], -2) != 'px'){ - $response[$key] = '100px'; - } - elseif(intval(str_replace('px', '', $response[$key])) < 1){ - $response[$key] = '100px'; - } - } - elseif($key == 'languages_variable' && $response[$key] == null){ - $response[$key] = 'languages'; - } - } - - header('Content-Type: application/json'); - echo json_encode($response); - } - - public function getAnswers($data){ - global $conn; - - $data['project_id'] = mysqli_real_escape_string($conn, $data['project_id']); - $data['field_name'] = mysqli_real_escape_string($conn, $data['field_name']); - - $metaDataTableName = $this->getMetaDataTableName($data['project_id']); - - if($data['matrix'] == 1){ - $query = "SELECT element_enum, element_type, element_validation_type, element_validation_min, element_validation_max FROM $metaDataTableName - WHERE project_id = " . intval($data['project_id']) . " - AND grid_name LIKE '" . $data['field_name'] . "' - LIMIT 1"; - } - else{ - $query = "SELECT element_enum, element_type, element_validation_type FROM $metaDataTableName - WHERE project_id = " . intval($data['project_id']) . " - AND field_name LIKE '" . $data['field_name'] . "'"; - } - $result = mysqli_query($conn, $query); - - $row = mysqli_fetch_array($result); - - if(strpos(' \n ', $row['element_enum']) !== false){ - $tmp = explode(' \n ', $row['element_enum']); - } - else{ - $tmp = explode('\n', $row['element_enum']); - } - - foreach($tmp AS $key => $value){ - $tmp2 = explode(',', $value); - $response[trim($tmp2[0])] = trim($tmp2[1]); - } - - if($row['element_type'] == 'text' && (strpos($row['element_validation_type'], 'date') !== false || strpos($row['element_validation_type'], 'time') !== false)){ - $response = null; - $response['0'] = 'Answer'; - } - elseif($row['element_type'] == 'file' && strpos($row['element_validation_type'], 'signature') !== false){ - $response = null; - $response['0'] = 'Answer'; - } - elseif($row['element_type'] == 'file' && $row['element_validation_type'] == null){ - $response = null; - $response['0'] = 'Answer'; - } - elseif($row['element_type'] == 'calc'){ - $response = null; - $response[""] = ""; - } - elseif($row['element_type'] == 'yesno'){ - $response = null; - $response['0'] = "No"; - $response['1'] = "Yes"; - } - elseif($row['element_type'] == 'truefalse'){ - $response = null; - $response['0'] = "False"; - $response['1'] = "True"; - } - elseif($row['element_type'] == 'slider'){ - $response = explode('|', array_keys($response)[0]); - $response = array_map('trim',$response); - if (count($response) == 3){$keys = array('0', '50', '100');} - elseif(count($response) == 2){$keys = array('0', '100');} - elseif(count($response) == 1){$keys = array('0');} - else{$keys = array();} - $response = array_combine($keys, $response); - } - - header('Content-Type: application/json'); - echo json_encode($response); - } - - public function getTranslations($data, $projectSettings){ - global $conn; - $layout_set = 0; - - $data['project_id'] = mysqli_real_escape_string($conn, $data['project_id']); - $data['page'] = mysqli_real_escape_string($conn, $data['page']); - - $metaDataTableName = $this->getMetaDataTableName($data['project_id']); - - $query = "SELECT field_name, element_type, misc, grid_name, element_validation_type, element_validation_min, element_validation_max, element_label FROM $metaDataTableName - WHERE project_id = " . intval($data['project_id']) - . ($data['page'] !='' ? " AND (form_name LIKE '" . $data['page'] . "' OR field_name LIKE 'survey_text_" . $data['page'] . "')" : ''); - $result = mysqli_query($conn, $query); - - while($row = mysqli_fetch_array($result)){ - //default questions - $response['defaults'][$row['field_name']] = strip_tags($row['element_label']. '
'); - - //$misc = explode("@", $row['misc']); - $misc = str_getcsv($row['misc'], '@'); - //$response['test'] = $misc; - - $response['all'][$row['field_name']] = $misc; - foreach($misc AS $key => $value){ - //replace ___ with @ - $value = str_replace('___', '@', $value); - - //questions - if(strpos($value, 'p1000lang') !== false){ - $value = trim(str_replace('p1000lang', '', $value)); - $value = json_decode($value, true); - foreach($value AS $key2 => $trans){ - if($key2 == $data['lang']){ - $response['questions'][$row['field_name']]['text'] = Piping::replaceVariablesInLabel($trans, ($data['record_id'] ? $data['record_id'] : '0'), $data['event_id']); - if(strpos($row['element_validation_type'], 'date') !== false){ - $response['questions'][$row['field_name']]['type'] = 'date'; - } - elseif(strpos($row['element_validation_type'], 'time') !== false){ - $response['questions'][$row['field_name']]['type'] = 'time'; - } - else{ - $response['questions'][$row['field_name']]['type'] = $row['element_type']; - } - $response['questions'][$row['field_name']]['matrix'] = $row['grid_name']; - - //layout - if($layout_set == 0){ - if(\CMH\Multilingual\Multilingual::is_arabic($trans) === true){ - $response['layout'] = 'rtl'; - } - else{ - $response['layout'] = 'ltr'; - } - $layout_set = 1; - } - } - } - } - - //answers - elseif(strpos($value, 'p1000answers') !== false){ - $value = trim(str_replace('p1000answers', '', $value)); - - $value = json_decode($value, true); - foreach($value AS $key2 => $trans){ - if($key2 == $data['lang']){ - foreach($trans AS $key3 => $newTrans){ - if($row['element_type'] == 'select'){ - $trans[$key3] = strip_tags(Piping::replaceVariablesInLabel($newTrans, ($data['record_id'] ? $data['record_id'] : '0'), $data['event_id']), '
'); - } - else{ - $trans[$key3] = Piping::replaceVariablesInLabel($newTrans, ($data['record_id'] ? $data['record_id'] : '0'), $data['event_id']); - } - } - - $response['answers'][$row['field_name']]['text'] = $trans; - if(strpos($row['element_validation_type'], 'date') !== false){ - $response['answers'][$row['field_name']]['type'] = 'date'; - } - elseif(strpos($row['element_validation_type'], 'time') !== false){ - $response['answers'][$row['field_name']]['type'] = 'time'; - } - elseif(strpos($row['element_validation_type'], 'signature') !== false){ - $response['answers'][$row['field_name']]['type'] = 'signature'; - } - else{ - $response['answers'][$row['field_name']]['type'] = $row['element_type']; - } - $response['answers'][$row['field_name']]['matrix'] = $row['grid_name']; - } - } - } - //errors - elseif(strpos($value, 'p1000errors') !== false){ - $value = trim(str_replace('p1000errors', '', $value)); - $value = json_decode($value, true); - foreach($value AS $key2 => $trans){ - if($key2 == $data['lang']){ - $response['errors'][$row['field_name']]['text'] = $trans; - if(strpos($row['element_validation_type'], 'date') !== false){ - $response['errors'][$row['field_name']]['type'] = 'date'; - } - else{ - $response['errors'][$row['field_name']]['type'] = $row['element_type']; - } - $response['errors'][$row['field_name']]['matrix'] = $row['grid_name']; - } - } - } - //field notes - elseif(strpos($value, 'p1000notes') !== false){ - $value = str_replace('p1000notes', '', $value); - $value = json_decode($value, true); - foreach($value AS $key2 => $trans){ - if($key2 == $data['lang']){ - $response['notes'][$row['field_name']]['text'] = Piping::replaceVariablesInLabel($trans, ($data['record_id'] ? $data['record_id'] : '0'), $data['event_id']); - } - } - } - //survey tranlations - elseif(strpos($value, 'p1000surveytext') !== false){ - $value = trim(str_replace('p1000surveytext', '', $value)); - $value = json_decode($value, true); - foreach($value AS $key2 => $trans){ - if($key2 == $data['lang']){ - foreach($trans AS $survey_id => $survey_text){ - $response['surveytext'][$survey_id] = $survey_text; - } - } - } - } - } - - // if error message is not set - if(!isset($response['errors'][$row['field_name']])){ - // if it is a text field with validation - if($row['element_type'] == 'text' && !empty($row['element_validation_type'])){ - - // Make array of error messages from project settings if not already made - if (!isset($defaultError)){ - // make array of default error prompts - $defaultError = array(); - $defaultError = array_fill_keys($projectSettings['validation'], NULL); - - foreach($projectSettings['validation'] AS $key => $valid_type){ - $defaultError[$valid_type] = array_combine($projectSettings['lang'][$key], $projectSettings['error'][$key]); - } - } - - // If the text field's validation matches with any defined default error messages, use the default error messages - if (array_key_exists($row['element_validation_type'], $defaultError)){ - if (array_key_exists($data['lang'], $defaultError[$row['element_validation_type']])){ - - // Check if the variable contains "[validation_range]", if so, pipe it with the actual range. - if (strpos($defaultError[$row['element_validation_type']][$data['lang']], "[validation_range]") !== false){ - - if (empty($row['element_validation_min']) && empty($row['element_validation_max'])){ - $validationRange = ''; - } else { - $validationRange = '('.$row['element_validation_min'].' - '.$row['element_validation_max'].')'; - } - - $response['errors'][$row['field_name']]['text'] = str_replace("[validation_range]", $validationRange, $defaultError[$row['element_validation_type']][$data['lang']]); - } else { - $response['errors'][$row['field_name']]['text'] = $defaultError[$row['element_validation_type']][$data['lang']]; - } - } - } - } - } - } - - // override - $instruments = $this->getProjectSetting('instruments'); - if (!empty($instruments)) { - $instruments = json_decode($instruments); - $form_name = $data['page']; - $this_lang = $data['lang']; - $simple_settings = $instruments->$form_name->$this_lang; - if (!empty($simple_settings)) { - $general_settings = $simple_settings->survey_settings; - if (!empty($general_settings)) { - if (!empty($general_settings->title) || $general_settings->title == "") - $response['surveytext']['surveytitle'] = html_entity_decode($general_settings->title); - if (!empty($general_settings->instructions) || $general_settings->instructions == "") - $response['surveytext']['surveyinstructions'] = html_entity_decode($general_settings->instructions); - if (!empty($general_settings->acknowledgement) || $general_settings->acknowledgement == "") - $response['surveytext']['surveyacknowledgment'] = html_entity_decode($general_settings->acknowledgement); - } - } - } - - //update language field - $response['exist'] = $this->updateLangVar($data); - $response['table'] = $metaDataTableName; - - header('Content-Type: application/json'); - echo json_encode($response); - } - - public function getRecordVar($data){ - global $conn; - - $data['project_id'] = mysqli_real_escape_string($conn, $data['project_id']); - - $metaDataTableName = $this->getMetaDataTableName($data['project_id']); - - $query = "SELECT field_name FROM $metaDataTableName where project_id = " . intval($data['project_id']) . " ORDER BY field_order LIMIT 1"; - $result = mysqli_query($conn, $query); - $row = mysqli_fetch_array($result); - - return $row['field_name']; - } - - public function getSavedLang($data){ - if($data['record_id'] != ''){ - $langVar = $this->getProjectSetting('languages_variable', $data['project_id']); - $tmp = json_decode(REDCap::getData($data['project_id'], 'json', array($data['record_id']), array($langVar)),true); - if(!empty($tmp)){ - header('Content-Type: application/json'); - echo json_encode($tmp[0][$langVar]); - } - else{ - return null; - } - } - else{ - return null; - } - - } - - public function updateLangVar($data){ - if($data['record_id'] != ''){ - $exist = json_decode(\REDCap::getData($data['project_id'], 'json', $data['record_id']), true); - if(!empty($exist)){ - $recordVar = $this->getRecordVar($data); - $langVar = $this->getProjectSetting('languages_variable', $data['project_id']); - - $t = array($recordVar => $data['record_id'], ($langVar != null ? $langVar : 'languages') => $data['lang_id'], 'redcap_event_name' => $this->getEventName($data['event_id'])); - $json_data = json_encode(array($t)); - $tmp = \REDCap::saveData($data['project_id'], 'json', $json_data, 'normal'); - - return $tmp; - } - } - } - - public function getEventName($event_id){ - global $conn; - - $query = "SELECT descrip, arm_id FROM redcap_events_metadata WHERE event_id = " . intval($event_id); - $result = mysqli_query($conn, $query); - $row = mysqli_fetch_array($result); - - $event_name = strtolower(str_replace(" ", "_", $row['descrip'])); - - $query = "SELECT arm_name FROM redcap_events_arms WHERE arm_id = " . intval($row['arm_id']); - $result = mysqli_query($conn, $query); - $row = mysqli_fetch_array($result); - - $event_name .= '_' . strtolower(str_replace(" ", "_", $row['arm_name'])); - - return $event_name; - } - - //copied from php.net - public function uniord($u) { - // i just copied this function fron the php.net comments, but it should work fine! - $k = mb_convert_encoding($u, 'UCS-2LE', 'UTF-8'); - $k1 = ord(substr($k, 0, 1)); - $k2 = ord(substr($k, 1, 1)); - return $k2 * 256 + $k1; - } - //copied from stackoverflow - public function is_arabic($str) { - if(mb_detect_encoding($str) !== 'UTF-8') { - $str = mb_convert_encoding($str,mb_detect_encoding($str),'UTF-8'); - } - - /* - $str = str_split($str); <- this function is not mb safe, it splits by bytes, not characters. we cannot use it - $str = preg_split('//u',$str); <- this function woulrd probably work fine but there was a bug reported in some php version so it pslits by bytes and not chars as well - */ - preg_match_all('/.|\n/u', $str, $matches); - $chars = $matches[0]; - $arabic_count = 0; - $latin_count = 0; - $total_count = 0; - foreach($chars as $char) { - //$pos = ord($char); we cant use that, its not binary safe - $pos = \CMH\Multilingual\Multilingual::uniord($char); - //echo $char ." --> ".$pos.PHP_EOL; - - if($pos >= 1536 && $pos <= 1791) { - $arabic_count++; - } else if($pos > 123 && $pos < 123) { - $latin_count++; - } - $total_count++; - } - if(($arabic_count/$total_count) > 0.6) { - // 60% arabic chars, its probably arabic - return true; - } - return false; - } - - public function getLanguages($project_id){ - $langVar = $this->languageVariable($project_id); - if(!$langVar){ - $langVar = 'languages'; - } - - $q = "SELECT element_enum FROM redcap_metadata WHERE project_id = " . intval($project_id) . " AND field_name = '" . $langVar . "'"; - $query = db_query($q); - $row = db_fetch_assoc($query); - - $tmp = explode(' \n ', $row['element_enum']); - foreach($tmp AS $key => $value){ - $tmp2 = explode(',', $value); - $response[trim($tmp2[0])] = trim($tmp2[1]); - } - - return $response; - } - - public function getData($project_id, $record){ - $q = "SELECT record, event_id, field_name, `value` FROM redcap_data - WHERE project_id = " . intval($project_id) . - " AND record = '" . $record . "'"; - $query = db_query($q); - - while($row = db_fetch_assoc($query)){ - $response[$row['record']][$row['event_id']][$row['field_name']] = $row['value']; - } - - return $response; - } - - public function getMetaData($project_id, $form = null){ - $q = "SELECT * FROM redcap_metadata - WHERE project_id = " . intval($project_id) - . ($form ? " AND form_name = '" . $form . "'" : "") . - " ORDER BY field_order"; - $query = db_query($q); - - while($row = db_fetch_assoc($query)){ - $response[] = $row; - } - - return $response; - } - - public function exportData($pid, $lang){ - global $conn; - - $langVar = $this->getProjectSetting('languages_variable', $pid); - if($langVar == ''){ - $langVar = 'languages'; - } - - ini_set('memory_limit','100M'); - set_time_limit(0); - - $lang = mysqli_real_escape_string($conn, $lang); - $pid = mysqli_real_escape_string($conn, $pid); - - $metaDataTableName = $this->getMetaDataTableName($pid); - - //language - $query = "SELECT element_enum, element_type, element_validation_type FROM $metaDataTableName - WHERE project_id = " . intval($pid) . " - AND field_name LIKE '" . $langVar . "'"; - $result = mysqli_query($conn, $query); - $row = mysqli_fetch_array($result); - - $tmp = explode(' \n ', $row['element_enum']); - foreach($tmp AS $key => $value){ - $tmp2 = explode(',', $value); - if($tmp2[0] == $lang){ - $response['language'] = trim($tmp2[1]); - break; - } - } - - //translations - $query = "SELECT field_name, element_type, misc, grid_name, element_validation_type, element_label FROM $metaDataTableName - WHERE project_id = " . intval($pid) . " AND field_name NOT LIKE 'survey_text%' ORDER BY field_order"; - $result = mysqli_query($conn, $query); - - while($row = mysqli_fetch_array($result)){ - $misc = explode('@', $row['misc']); - - foreach($misc AS $key => $value){ - //replace ___ with @ - $value = str_replace('___', '@', $value); - - //questions - if(strpos($value, 'p1000lang') !== false){ - $value = trim(str_replace('p1000lang', '', $value)); - $value = json_decode($value, true); - foreach($value AS $key2 => $trans){ - if($key2 == $response['language']){ - $response['questions'][$row['field_name']]['text'] = $trans; - if(strpos($row['element_validation_type'], 'date') !== false){ - $response['questions'][$row['field_name']]['type'] = 'date'; - } - else{ - $response['questions'][$row['field_name']]['type'] = $row['element_type']; - } - $response['questions'][$row['field_name']]['matrix'] = $row['grid_name']; - } - } - } - //answers - elseif(strpos($value, 'p1000answers') !== false){ - $value = trim(str_replace('p1000answers', '', $value)); - $value = json_decode($value, true); - foreach($value AS $key2 => $trans){ - if($key2 == $response['language']){ - $response['answers'][$row['field_name']]['text'] = $trans; - if(strpos($row['element_validation_type'], 'date') !== false){ - $response['answers'][$row['field_name']]['type'] = 'date'; - } - elseif(strpos($row['element_validation_type'], 'signature') !== false){ - $response['answers'][$row['field_name']]['type'] = 'signature'; - } - else{ - $response['answers'][$row['field_name']]['type'] = $row['element_type']; - } - $response['answers'][$row['field_name']]['matrix'] = $row['grid_name']; - } - } - } - } - - //non translated fields - if(!isset($response['questions'][$row['field_name']])){ - $response['questions'][$row['field_name']]['text'] = $row['element_label']; - $response['questions'][$row['field_name']]['type'] = 'text'; - } - } - - //header - //$data = '"record_id",'; - foreach($response['questions'] AS $field_name => $values){ - if($values['type'] == 'checkbox'){ - foreach($response['answers'][$field_name]['text'] AS $key => $text){ - $data .= '"' . strip_tags($values['text']) . ': ' . $text . '",'; - } - } - else{ - $data .= '"' . strip_tags($values['text']) . '",'; - } - } - $data .= "\r\n"; - - //data - $query = "SELECT record, field_name, instance, value FROM redcap_data WHERE project_id = " . $pid . " ORDER BY record"; - $result = mysqli_query($conn, $query); - - while($row = mysqli_fetch_array($result)){ - if($response['questions'][$row['field_name']]['type'] == 'checkbox'){ - $myData[$row['record']][($row['instance'] == null ? 1 : $row['instance'])][$row['field_name'] . '___' . $row['value']] = 1; - } - else{ - $myData[$row['record']][($row['instance'] == null ? 1 : $row['instance'])][$row['field_name']] = $row['value']; - } - } - - //format - foreach($myData AS $record => $values){ - foreach($values AS $instance => $vals){ - //$data .= '"' . $record . '",'; - foreach($response['questions'] AS $field_name => $vars){ - if($vars['type'] == 'checkbox'){ - foreach($response['answers'][$field_name]['text'] AS $key => $text){ - $data .= '"' . $myData[$record][$instance][$field_name . '___' . $key] . '",'; - } - } - elseif(in_array($response['answers'][$field_name]['type'], array('radio','select','yesno','truefalse'))){ - $data .= '"' . $response['answers'][$field_name]['text'][$myData[$record][$instance][$field_name]] . '",'; - } - else{ - $data .= '"' . $myData[$record][$instance][$field_name] . '",'; - } - } - $data .= "\r\n"; - } - } - - //export - header("Content-type: text/csv"); - header("Content-Disposition: attachment; filename=\"Multilingual" . ''/*\REDCap::getProjectTitle($pid)*/ . " DATA (" . $response['language'] . ") " . date('Y-m-d Hi') . ".csv\""); - header("Pragma: no-cache"); - header("Expires: 0"); - - echo $data; - } - - public function getUserSelectedLanguages($record) { - $user_languages = []; - - $result = $this->queryLogs("SELECT timestamp, message, record_id, language_value, instrument, event_id - WHERE message = ? AND record_id = ?", [ - "user_selected_language", - $record - ]); - - while($row = db_fetch_assoc($result)) { - $instrument = $row['instrument']; - $language_value = $row['language_value']; - $event_id = $row['event_id']; - - if (!empty($instrument) && !empty($language_value) && !empty($event_id)) { - if (empty($user_languages[$event_id])) { - $user_languages[$event_id] = []; - } - if (empty($user_languages[$event_id][$instrument])) { - $user_languages[$event_id][$instrument] = $language_value; - } - } - } - - return $user_languages; - } - - public function translatePDF(&$metadata, $user_languages) { - // translate survey instructions/titles - global $Proj; - $instruments = json_decode($this->getProjectSetting('instruments')); - if ($instruments && !empty($instruments)) { - foreach ($Proj->surveys as $id => &$survey) { - // determine which language to use for this form - $lang = ''; - $form_name = $survey['form_name']; - foreach($user_languages as $event_id => $event) { - if (!empty($event[$form_name])) { - $lang = $event[$form_name]; - break; - } - } - if ($lang == '') { - continue; - } - - if (!empty($instruments->$form_name->$lang->survey_settings->title)) { - $survey['title'] = $instruments->$form_name->$lang->survey_settings->title; - } - if (!empty($instruments->$form_name->$lang->survey_settings->acknowledgement)) { - $survey['instructions'] = $instruments->$form_name->$lang->survey_settings->acknowledgement; - } - } - } - - // translate field question/answer labels - foreach($metadata as &$field) { - // see which instrument this field belongs to - $parent_form = $field['form_name']; - $field_name = $field['field_name']; - - // get question and answer translations for this field - $translations = $this->getFieldTranslations($field); - - // determine which language to use for that field - $lang = ''; - foreach($user_languages as $event_id => $event) { - if (!empty($event[$parent_form])) { - $lang = $event[$parent_form]; - break; - } - } - if ($lang == '') { - continue; - } - - // determine the translated field label for this field/lang combo - if ($translations['lang'] && $translations['lang'][$lang]) { - $field['element_label'] = $translations['lang'][$lang]; - } - - // determine the translated answer labels for this field/lang combo - if ($translations['answers'] && $translations['answers'][$lang]) { - foreach($translations['answers'][$lang] as $raw => $translation) { - $translations['answers'][$lang][$raw] = "$raw, $translation"; - } - $field['element_enum'] = implode(" \\n ", $translations['answers'][$lang]); - } - } - - return $metadata; - } - - public function getFieldTranslations($field_array) { - // this function returns an array like: - /* - translations = [ - 'lang' => [ - 'English' => 'My Field Label', - 'Espanol' => 'Mi etiqueta de campo' - ], - 'answers' => [ - 'English' => [ - '0' => 'Zero', - '1' => 'One', - '2' => 'Two' - ], - 'Espanol' => [ - '0' => 'Cero', - '1' => 'Uno', - '2' => 'Dos' - ], - ] - ] - - assuming $field_array passed has 'misc' field with relevant @p1000lang and @p1000answers information - */ - $translations = []; - $field_misc = $field_array['misc']; - - // determine indexes for p1000lang and p1000answers - $regex_capture_p1000 = "/p1000([^{]*)/m"; - preg_match_all($regex_capture_p1000, $field_misc, $indexes); - $indexes = $indexes[1]; - - // capture pieces of field['misc'] that are contained in balanced curly braces (inclusive) - $regex_capture_balanced_braces = "/\{(?:[^}{]+|(?R))*+\}/m"; - preg_match_all($regex_capture_balanced_braces, $field_misc, $matches); - if (gettype($matches) == 'array') { - $matches = $matches[0]; - - // decode lang json (if applicable) - $lang_index = array_search('lang', $indexes, true); - if ($lang_index !== false) { - $translations['lang'] = json_decode($matches[$lang_index], true); - } - - // decode answers json (if applicable) - $answers_index = array_search('answers', $indexes, true); - if ($answers_index !== false) { - $translations['answers'] = json_decode($matches[$answers_index], true); - } - } - - return $translations; - } - -} -?> +getProjectSetting('use-api-endpoint', $project_id); + + // add multilingual_survey.js after making text replacements + $redcap_survey_javascript = file_get_contents($this->getModulePath() . 'js/multilingual_survey.js'); + $redcap_survey_javascript = str_replace('REDCAP_PDF_URL', ($this->getProjectSetting('multilingual-econsent', $project_id) ? $this->getUrl("multilingualPDF.php", true, ($api_endpoint == true ? true : false)) : 'false') . '&id=' . $record . '&form=' . $instrument . '&event_id=' . $event_id . '&instance=' . $repeat_instance, $redcap_survey_javascript); + $redcap_survey_javascript = str_replace('APP_PATH_IMAGES', APP_PATH_IMAGES, $redcap_survey_javascript); + $redcap_survey_javascript = str_replace('REDCAP_INSTRUMENT_NAME', $instrument, $redcap_survey_javascript); + $redcap_survey_javascript = str_replace('MULTILINGUAL_RECORD_ID', $record, $redcap_survey_javascript); + $redcap_survey_javascript = str_replace('REDCAP_LANGUAGE_VARIABLE', $this->languageVariable($project_id), $redcap_survey_javascript); + $redcap_survey_javascript = str_replace('REDCAP_AJAX_URL', $this->getUrl("index.php", true, ($api_endpoint == true ? true : false)), $redcap_survey_javascript); + $redcap_survey_javascript = str_replace('MULTILINGUAL_LANGUAGE_SELECTED_URL', $this->getUrl('languageSelected.php'), $redcap_survey_javascript); + $redcap_survey_javascript = str_replace('MULTILINGUAL_SURVEY_EVENT', $event_id, $redcap_survey_javascript); + + // see if pdf translation is configured or not -- set variable in multilingual_survey.js + if ($this->getProjectSetting("translate_pdfs_instruments")) { + $redcap_survey_javascript = str_replace('MULTILINGUAL_PDF_TRANSLATION_ENABLED', 'true', $redcap_survey_javascript); + } else { + $redcap_survey_javascript = str_replace('MULTILINGUAL_PDF_TRANSLATION_ENABLED', 'false', $redcap_survey_javascript); + } + + echo ""; + echo ''; + } + + function redcap_survey_complete($project_id, $record, $instrument, $event_id, $group_id = NULL, $survey_hash, $response_id = NULL, $repeat_instance){ + $api_endpoint = $this->getProjectSetting('use-api-endpoint', $project_id); + // Update and add multilingual_survey_complete + echo ''; + } + + function redcap_data_entry_form($project_id, $record, $instrument){ + echo ''; + echo ''; + } + + function redcap_pdf($project_id, $metadata, $data, $instrument, $record, $event_id, $instance) { + // delay execution of this module to allow multi-consent-signature module to do it's thing + if ($this->delayModuleExecution()) { + return; + } + + // get which languages were selected for which instruments by the user as they were taking surveys + $user_langs = $this->getUserSelectedLanguages($record); + + if (empty($user_langs)) { + // user never selected a lang, do no translations + return array('metadata'=>$metadata, 'data'=>$data); + } + + // log to project event table + $action_description = "Translating Generated PDF"; + $changes_made = "The Multilingual module will translate field labels (for each instrument) based on language selections the user made in survey(s)."; + \REDCap::logEvent($action_description, $changes_made, null, $record_id, $event_id); + + // translate metadata using user selected languages + global $Proj; + $translated_metadata = $this->translatePDF($metadata, $user_langs); + + return array('metadata'=>$translated_metadata, 'data'=>$data); + } + + function redcap_every_page_top($project_id){ + $api_endpoint = $this->getProjectSetting('use-api-endpoint', $project_id); + $at_survey_settings = strpos($_SERVER['REQUEST_URI'], 'Surveys/edit_info.php') !== false || strpos($_SERVER['REQUEST_URI'], 'Surveys/create_survey.php') !== false; + + //$user_rights = REDCap::getUserRights(); + //echo json_encode($user_rights); + + if(strpos($_SERVER['REQUEST_URI'], 'online_designer.php') !== false && isset($_GET['page'])){ + echo ''; + echo ''; + } + elseif(strpos($_SERVER['REQUEST_URI'], 'DataExport/index.php') !== false){ + echo ''; + } + elseif($_GET['__return'] == 1 or (isset($_GET['s']) && !isset($_GET['__page__']))){ + $instrument = $_GET['page']; + echo ''; + + echo ''; + } + elseif(strpos($_SERVER['REQUEST_URI'], 'DataEntry/index.php') !== false || strpos($_SERVER['REQUEST_URI'], 'DataEntry/record_home.php') !== false){ + echo ''; + echo ''; + } + elseif($at_survey_settings && isset($_GET['page'])){ + $index_url = $this->getUrl("index.php", true, ($api_endpoint == true ? true : false)); + $language_var = $this->languageVariable($project_id); + $stylesheet = ''; + $ml_survey_settings_js = ''; + $ml_survey_settings_js = str_replace('REDCAP_AJAX_URL', $index_url, $ml_survey_settings_js); + $ml_survey_settings_js = str_replace('REDCAP_LANGUAGE_VARIABLE', $language_var, $ml_survey_settings_js); + + echo $stylesheet; + echo $ml_survey_settings_js; + } + } + + /** + * @param $projectId + * @return string + */ + private function getMetaDataTableName($projectId){ + global $conn; + if($this->getProjectSetting('use-drafted-changes', $projectId)){ + $query = "select draft_mode from redcap_projects where project_id = " . mysqli_real_escape_string($conn, $data['project_id']); + if($result = mysqli_query($conn, $query)){ + if($row = mysqli_fetch_array($result)){ + $draftMode = $row["draft_mode"]; + return "redcap_metadata".($draftMode == 1?"_temp":""); + }else{ + error_log("Multilingual: no row to determine draft_mode"); + } + mysqli_free_result($result); + }else{ + error_log("Multilingual: no result to determine draft_mode"); + } + } + return "redcap_metadata"; + } + + public function languageVariable($project_id){ + $langVar = $this->getProjectSetting('languages_variable', $project_id); + if($langVar == ''){ + $langVar = 'languages'; + } + return $langVar; + } + + public function getSurveySettings($data) { + $instruments = $this->getProjectSetting('instruments'); + + if (!empty($instruments)) { + $instruments = json_decode($instruments); + $name = htmlspecialchars($data['instrument']); + $instrument = $instruments->$name; + } else { + $instruments = new \stdClass(); + } + + header('Content-Type: application/json'); + echo json_encode($instrument); + } + + public function saveSurveySettings($all_data) { + $instruments = $this->getProjectSetting('instruments'); + if (empty($instruments)) { + $instruments = new \stdClass(); + } else { + $instruments = json_decode($instruments); + } + + foreach ($all_data as $data) { + $instrument = htmlspecialchars($data['instrument']); + $lang = htmlspecialchars($data['language']); + if (empty($instruments->$instrument)) { + $instruments->$instrument = new \stdClass(); + } + if (empty($instruments->$instrument->$lang)) { + $instruments->$instrument->$lang = new \stdClass(); + } + foreach ($data['collections'] as $coll_name => $coll) { + $instruments->$instrument->$lang->$coll_name = new \stdClass(); + + // add each setting to collection after encoding HTML + foreach ($coll as $sname => $setting) { + $instruments->$instrument->$lang->$coll_name->$sname = htmlspecialchars($setting); + } + } + } + + $this->setProjectSetting('instruments', json_encode($instruments)); + } + + public function getSettings($data){ + $response = $this->getProjectSettings($data['project_id']); + + foreach($response AS $key => $values){ + if($key == 'button-width'){ + if(substr($response[$key], -2) != 'px'){ + $response[$key] = '100px'; + } + elseif(intval(str_replace('px', '', $response[$key])) < 1){ + $response[$key] = '100px'; + } + } + elseif($key == 'languages_variable' && $response[$key] == null){ + $response[$key] = 'languages'; + } + } + + header('Content-Type: application/json'); + echo json_encode($response); + } + + public function getAnswers($data){ + global $conn; + + $data['project_id'] = mysqli_real_escape_string($conn, $data['project_id']); + $data['field_name'] = mysqli_real_escape_string($conn, $data['field_name']); + + $metaDataTableName = $this->getMetaDataTableName($data['project_id']); + + if($data['matrix'] == 1){ + $query = "SELECT element_enum, element_type, element_validation_type, element_validation_min, element_validation_max FROM $metaDataTableName + WHERE project_id = " . intval($data['project_id']) . " + AND grid_name LIKE '" . $data['field_name'] . "' + LIMIT 1"; + } + else{ + $query = "SELECT element_enum, element_type, element_validation_type FROM $metaDataTableName + WHERE project_id = " . intval($data['project_id']) . " + AND field_name LIKE '" . $data['field_name'] . "'"; + } + $result = mysqli_query($conn, $query); + + $row = mysqli_fetch_array($result); + + if(strpos(' \n ', $row['element_enum']) !== false){ + $tmp = explode(' \n ', $row['element_enum']); + } + else{ + $tmp = explode('\n', $row['element_enum']); + } + + foreach($tmp AS $key => $value){ + $tmp2 = explode(',', $value); + $response[trim($tmp2[0])] = trim($tmp2[1]); + } + + if($row['element_type'] == 'text' && (strpos($row['element_validation_type'], 'date') !== false || strpos($row['element_validation_type'], 'time') !== false)){ + $response = null; + $response['0'] = 'Answer'; + } + elseif($row['element_type'] == 'file' && strpos($row['element_validation_type'], 'signature') !== false){ + $response = null; + $response['0'] = 'Answer'; + } + elseif($row['element_type'] == 'file' && $row['element_validation_type'] == null){ + $response = null; + $response['0'] = 'Answer'; + } + elseif($row['element_type'] == 'calc'){ + $response = null; + $response[""] = ""; + } + elseif($row['element_type'] == 'yesno'){ + $response = null; + $response['0'] = "No"; + $response['1'] = "Yes"; + } + elseif($row['element_type'] == 'truefalse'){ + $response = null; + $response['0'] = "False"; + $response['1'] = "True"; + } + elseif($row['element_type'] == 'slider'){ + $response = explode('|', array_keys($response)[0]); + $response = array_map('trim',$response); + if (count($response) == 3){$keys = array('0', '50', '100');} + elseif(count($response) == 2){$keys = array('0', '100');} + elseif(count($response) == 1){$keys = array('0');} + else{$keys = array();} + $response = array_combine($keys, $response); + } + + header('Content-Type: application/json'); + echo json_encode($response); + } + + public function getTranslations($data, $projectSettings){ + global $conn; + $layout_set = 0; + + $data['project_id'] = mysqli_real_escape_string($conn, $data['project_id']); + $data['page'] = mysqli_real_escape_string($conn, $data['page']); + + $metaDataTableName = $this->getMetaDataTableName($data['project_id']); + + $query = "SELECT field_name, element_type, misc, grid_name, element_validation_type, element_validation_min, element_validation_max, element_label FROM $metaDataTableName + WHERE project_id = " . intval($data['project_id']) + . ($data['page'] !='' ? " AND (form_name LIKE '" . $data['page'] . "' OR field_name LIKE 'survey_text_" . $data['page'] . "')" : ''); + $result = mysqli_query($conn, $query); + + while($row = mysqli_fetch_array($result)){ + //default questions + $response['defaults'][$row['field_name']] = strip_tags($row['element_label']. '
'); + + //$misc = explode("@", $row['misc']); + $misc = str_getcsv($row['misc'], '@'); + //$response['test'] = $misc; + + $response['all'][$row['field_name']] = $misc; + foreach($misc AS $key => $value){ + //replace ___ with @ + $value = str_replace('___', '@', $value); + + //questions + if(strpos($value, 'p1000lang') !== false){ + $value = trim(str_replace('p1000lang', '', $value)); + $value = json_decode($value, true); + foreach($value AS $key2 => $trans){ + if($key2 == $data['lang']){ + $response['questions'][$row['field_name']]['text'] = Piping::replaceVariablesInLabel($trans, ($data['record_id'] ? $data['record_id'] : '0'), $data['event_id']); + if(strpos($row['element_validation_type'], 'date') !== false){ + $response['questions'][$row['field_name']]['type'] = 'date'; + } + elseif(strpos($row['element_validation_type'], 'time') !== false){ + $response['questions'][$row['field_name']]['type'] = 'time'; + } + else{ + $response['questions'][$row['field_name']]['type'] = $row['element_type']; + } + $response['questions'][$row['field_name']]['matrix'] = $row['grid_name']; + + //layout + if($layout_set == 0){ + if(\CMH\Multilingual\Multilingual::is_arabic($trans) === true){ + $response['layout'] = 'rtl'; + } + else{ + $response['layout'] = 'ltr'; + } + $layout_set = 1; + } + } + } + } + + //answers + elseif(strpos($value, 'p1000answers') !== false){ + $value = trim(str_replace('p1000answers', '', $value)); + + $value = json_decode($value, true); + foreach($value AS $key2 => $trans){ + if($key2 == $data['lang']){ + foreach($trans AS $key3 => $newTrans){ + if($row['element_type'] == 'select'){ + $trans[$key3] = strip_tags(Piping::replaceVariablesInLabel($newTrans, ($data['record_id'] ? $data['record_id'] : '0'), $data['event_id']), '
'); + } + else{ + $trans[$key3] = Piping::replaceVariablesInLabel($newTrans, ($data['record_id'] ? $data['record_id'] : '0'), $data['event_id']); + } + } + + $response['answers'][$row['field_name']]['text'] = $trans; + if(strpos($row['element_validation_type'], 'date') !== false){ + $response['answers'][$row['field_name']]['type'] = 'date'; + } + elseif(strpos($row['element_validation_type'], 'time') !== false){ + $response['answers'][$row['field_name']]['type'] = 'time'; + } + elseif(strpos($row['element_validation_type'], 'signature') !== false){ + $response['answers'][$row['field_name']]['type'] = 'signature'; + } + else{ + $response['answers'][$row['field_name']]['type'] = $row['element_type']; + } + $response['answers'][$row['field_name']]['matrix'] = $row['grid_name']; + } + } + } + //errors + elseif(strpos($value, 'p1000errors') !== false){ + $value = trim(str_replace('p1000errors', '', $value)); + $value = json_decode($value, true); + foreach($value AS $key2 => $trans){ + if($key2 == $data['lang']){ + $response['errors'][$row['field_name']]['text'] = $trans; + if(strpos($row['element_validation_type'], 'date') !== false){ + $response['errors'][$row['field_name']]['type'] = 'date'; + } + else{ + $response['errors'][$row['field_name']]['type'] = $row['element_type']; + } + $response['errors'][$row['field_name']]['matrix'] = $row['grid_name']; + } + } + } + //field notes + elseif(strpos($value, 'p1000notes') !== false){ + $value = str_replace('p1000notes', '', $value); + $value = json_decode($value, true); + foreach($value AS $key2 => $trans){ + if($key2 == $data['lang']){ + $response['notes'][$row['field_name']]['text'] = Piping::replaceVariablesInLabel($trans, ($data['record_id'] ? $data['record_id'] : '0'), $data['event_id']); + } + } + } + //survey tranlations + elseif(strpos($value, 'p1000surveytext') !== false){ + $value = trim(str_replace('p1000surveytext', '', $value)); + $value = json_decode($value, true); + foreach($value AS $key2 => $trans){ + if($key2 == $data['lang']){ + foreach($trans AS $survey_id => $survey_text){ + $response['surveytext'][$survey_id] = $survey_text; + } + } + } + } + } + + // if error message is not set + if(!isset($response['errors'][$row['field_name']])){ + // if it is a text field with validation + if($row['element_type'] == 'text' && !empty($row['element_validation_type'])){ + + // Make array of error messages from project settings if not already made + if (!isset($defaultError)){ + // make array of default error prompts + $defaultError = array(); + $defaultError = array_fill_keys($projectSettings['validation'], NULL); + + foreach($projectSettings['validation'] AS $key => $valid_type){ + $defaultError[$valid_type] = array_combine($projectSettings['lang'][$key], $projectSettings['error'][$key]); + } + } + + // If the text field's validation matches with any defined default error messages, use the default error messages + if (array_key_exists($row['element_validation_type'], $defaultError)){ + if (array_key_exists($data['lang'], $defaultError[$row['element_validation_type']])){ + + // Check if the variable contains "[validation_range]", if so, pipe it with the actual range. + if (strpos($defaultError[$row['element_validation_type']][$data['lang']], "[validation_range]") !== false){ + + if (empty($row['element_validation_min']) && empty($row['element_validation_max'])){ + $validationRange = ''; + } else { + $validationRange = '('.$row['element_validation_min'].' - '.$row['element_validation_max'].')'; + } + + $response['errors'][$row['field_name']]['text'] = str_replace("[validation_range]", $validationRange, $defaultError[$row['element_validation_type']][$data['lang']]); + } else { + $response['errors'][$row['field_name']]['text'] = $defaultError[$row['element_validation_type']][$data['lang']]; + } + } + } + } + } + } + + // override + $instruments = $this->getProjectSetting('instruments'); + if (!empty($instruments)) { + $instruments = json_decode($instruments); + $form_name = $data['page']; + $this_lang = $data['lang']; + $simple_settings = $instruments->$form_name->$this_lang; + if (!empty($simple_settings)) { + $general_settings = $simple_settings->survey_settings; + if (!empty($general_settings)) { + if (!empty($general_settings->title) || $general_settings->title == "") + $response['surveytext']['surveytitle'] = html_entity_decode($general_settings->title); + if (!empty($general_settings->instructions) || $general_settings->instructions == "") + $response['surveytext']['surveyinstructions'] = html_entity_decode($general_settings->instructions); + if (!empty($general_settings->acknowledgement) || $general_settings->acknowledgement == "") + $response['surveytext']['surveyacknowledgment'] = html_entity_decode($general_settings->acknowledgement); + } + } + } + + //update language field + $response['exist'] = $this->updateLangVar($data); + $response['table'] = $metaDataTableName; + + header('Content-Type: application/json'); + echo json_encode($response); + } + + public function getRecordVar($data){ + global $conn; + + $data['project_id'] = mysqli_real_escape_string($conn, $data['project_id']); + + $metaDataTableName = $this->getMetaDataTableName($data['project_id']); + + $query = "SELECT field_name FROM $metaDataTableName where project_id = " . intval($data['project_id']) . " ORDER BY field_order LIMIT 1"; + $result = mysqli_query($conn, $query); + $row = mysqli_fetch_array($result); + + return $row['field_name']; + } + + public function getSavedLang($data){ + if($data['record_id'] != ''){ + $langVar = $this->getProjectSetting('languages_variable', $data['project_id']); + $tmp = json_decode(REDCap::getData($data['project_id'], 'json', array($data['record_id']), array($langVar)),true); + if(!empty($tmp)){ + header('Content-Type: application/json'); + echo json_encode($tmp[0][$langVar]); + } + else{ + return null; + } + } + else{ + return null; + } + + } + + public function updateLangVar($data){ + if($data['record_id'] != ''){ + $exist = json_decode(\REDCap::getData($data['project_id'], 'json', $data['record_id']), true); + if(!empty($exist)){ + $recordVar = $this->getRecordVar($data); + $langVar = $this->getProjectSetting('languages_variable', $data['project_id']); + + $t = array($recordVar => $data['record_id'], ($langVar != null ? $langVar : 'languages') => $data['lang_id'], 'redcap_event_name' => $this->getEventName($data['event_id'])); + $json_data = json_encode(array($t)); + $tmp = \REDCap::saveData($data['project_id'], 'json', $json_data, 'normal'); + + return $tmp; + } + } + } + + public function getEventName($event_id){ + global $conn; + + $query = "SELECT descrip, arm_id FROM redcap_events_metadata WHERE event_id = " . intval($event_id); + $result = mysqli_query($conn, $query); + $row = mysqli_fetch_array($result); + + $event_name = strtolower(str_replace(" ", "_", $row['descrip'])); + + $query = "SELECT arm_name FROM redcap_events_arms WHERE arm_id = " . intval($row['arm_id']); + $result = mysqli_query($conn, $query); + $row = mysqli_fetch_array($result); + + $event_name .= '_' . strtolower(str_replace(" ", "_", $row['arm_name'])); + + return $event_name; + } + + //copied from php.net + public function uniord($u) { + // i just copied this function fron the php.net comments, but it should work fine! + $k = mb_convert_encoding($u, 'UCS-2LE', 'UTF-8'); + $k1 = ord(substr($k, 0, 1)); + $k2 = ord(substr($k, 1, 1)); + return $k2 * 256 + $k1; + } + //copied from stackoverflow + public function is_arabic($str) { + if(mb_detect_encoding($str) !== 'UTF-8') { + $str = mb_convert_encoding($str,mb_detect_encoding($str),'UTF-8'); + } + + /* + $str = str_split($str); <- this function is not mb safe, it splits by bytes, not characters. we cannot use it + $str = preg_split('//u',$str); <- this function woulrd probably work fine but there was a bug reported in some php version so it pslits by bytes and not chars as well + */ + preg_match_all('/.|\n/u', $str, $matches); + $chars = $matches[0]; + $arabic_count = 0; + $latin_count = 0; + $total_count = 0; + foreach($chars as $char) { + //$pos = ord($char); we cant use that, its not binary safe + $pos = \CMH\Multilingual\Multilingual::uniord($char); + //echo $char ." --> ".$pos.PHP_EOL; + + if($pos >= 1536 && $pos <= 1791) { + $arabic_count++; + } else if($pos > 123 && $pos < 123) { + $latin_count++; + } + $total_count++; + } + if(($arabic_count/$total_count) > 0.6) { + // 60% arabic chars, its probably arabic + return true; + } + return false; + } + + public function getLanguages($project_id){ + $langVar = $this->languageVariable($project_id); + if(!$langVar){ + $langVar = 'languages'; + } + + $q = "SELECT element_enum FROM redcap_metadata WHERE project_id = " . intval($project_id) . " AND field_name = '" . $langVar . "'"; + $query = db_query($q); + $row = db_fetch_assoc($query); + + $tmp = explode(' \n ', $row['element_enum']); + foreach($tmp AS $key => $value){ + $tmp2 = explode(',', $value); + $response[trim($tmp2[0])] = trim($tmp2[1]); + } + + return $response; + } + + public function getMetaData2($project_id, $form = null){ + $q = "SELECT * FROM redcap_metadata + WHERE project_id = " . intval($project_id) + . ($form ? " AND form_name = '" . $form . "'" : "") . + " ORDER BY field_order"; + $query = db_query($q); + + while($row = db_fetch_assoc($query)){ + $response[] = $row; + } + + return $response; + } + + public function exportData($pid, $lang){ + global $conn; + + $langVar = $this->getProjectSetting('languages_variable', $pid); + if($langVar == ''){ + $langVar = 'languages'; + } + + ini_set('memory_limit','100M'); + set_time_limit(0); + + $lang = mysqli_real_escape_string($conn, $lang); + $pid = mysqli_real_escape_string($conn, $pid); + + $metaDataTableName = $this->getMetaDataTableName($pid); + + //language + $query = "SELECT element_enum, element_type, element_validation_type FROM $metaDataTableName + WHERE project_id = " . intval($pid) . " + AND field_name LIKE '" . $langVar . "'"; + $result = mysqli_query($conn, $query); + $row = mysqli_fetch_array($result); + + $tmp = explode(' \n ', $row['element_enum']); + foreach($tmp AS $key => $value){ + $tmp2 = explode(',', $value); + if($tmp2[0] == $lang){ + $response['language'] = trim($tmp2[1]); + break; + } + } + + //translations + $query = "SELECT field_name, element_type, misc, grid_name, element_validation_type, element_label FROM $metaDataTableName + WHERE project_id = " . intval($pid) . " AND field_name NOT LIKE 'survey_text%' ORDER BY field_order"; + $result = mysqli_query($conn, $query); + + while($row = mysqli_fetch_array($result)){ + $misc = explode('@', $row['misc']); + + foreach($misc AS $key => $value){ + //replace ___ with @ + $value = str_replace('___', '@', $value); + + //questions + if(strpos($value, 'p1000lang') !== false){ + $value = trim(str_replace('p1000lang', '', $value)); + $value = json_decode($value, true); + foreach($value AS $key2 => $trans){ + if($key2 == $response['language']){ + $response['questions'][$row['field_name']]['text'] = $trans; + if(strpos($row['element_validation_type'], 'date') !== false){ + $response['questions'][$row['field_name']]['type'] = 'date'; + } + else{ + $response['questions'][$row['field_name']]['type'] = $row['element_type']; + } + $response['questions'][$row['field_name']]['matrix'] = $row['grid_name']; + } + } + } + //answers + elseif(strpos($value, 'p1000answers') !== false){ + $value = trim(str_replace('p1000answers', '', $value)); + $value = json_decode($value, true); + foreach($value AS $key2 => $trans){ + if($key2 == $response['language']){ + $response['answers'][$row['field_name']]['text'] = $trans; + if(strpos($row['element_validation_type'], 'date') !== false){ + $response['answers'][$row['field_name']]['type'] = 'date'; + } + elseif(strpos($row['element_validation_type'], 'signature') !== false){ + $response['answers'][$row['field_name']]['type'] = 'signature'; + } + else{ + $response['answers'][$row['field_name']]['type'] = $row['element_type']; + } + $response['answers'][$row['field_name']]['matrix'] = $row['grid_name']; + } + } + } + } + + //non translated fields + if(!isset($response['questions'][$row['field_name']])){ + $response['questions'][$row['field_name']]['text'] = $row['element_label']; + $response['questions'][$row['field_name']]['type'] = 'text'; + } + } + + //header + //$data = '"record_id",'; + foreach($response['questions'] AS $field_name => $values){ + if($values['type'] == 'checkbox'){ + foreach($response['answers'][$field_name]['text'] AS $key => $text){ + $data .= '"' . strip_tags($values['text']) . ': ' . $text . '",'; + } + } + else{ + $data .= '"' . strip_tags($values['text']) . '",'; + } + } + $data .= "\r\n"; + + //data + $query = "SELECT record, field_name, instance, value FROM redcap_data WHERE project_id = " . $pid . " ORDER BY record"; + $result = mysqli_query($conn, $query); + + while($row = mysqli_fetch_array($result)){ + if($response['questions'][$row['field_name']]['type'] == 'checkbox'){ + $myData[$row['record']][($row['instance'] == null ? 1 : $row['instance'])][$row['field_name'] . '___' . $row['value']] = 1; + } + else{ + $myData[$row['record']][($row['instance'] == null ? 1 : $row['instance'])][$row['field_name']] = $row['value']; + } + } + + //format + foreach($myData AS $record => $values){ + foreach($values AS $instance => $vals){ + //$data .= '"' . $record . '",'; + foreach($response['questions'] AS $field_name => $vars){ + if($vars['type'] == 'checkbox'){ + foreach($response['answers'][$field_name]['text'] AS $key => $text){ + $data .= '"' . $myData[$record][$instance][$field_name . '___' . $key] . '",'; + } + } + elseif(in_array($response['answers'][$field_name]['type'], array('radio','select','yesno','truefalse'))){ + $data .= '"' . $response['answers'][$field_name]['text'][$myData[$record][$instance][$field_name]] . '",'; + } + else{ + $data .= '"' . $myData[$record][$instance][$field_name] . '",'; + } + } + $data .= "\r\n"; + } + } + + //export + header("Content-type: text/csv"); + header("Content-Disposition: attachment; filename=\"Multilingual" . ''/*\REDCap::getProjectTitle($pid)*/ . " DATA (" . $response['language'] . ") " . date('Y-m-d Hi') . ".csv\""); + header("Pragma: no-cache"); + header("Expires: 0"); + + echo $data; + } + + public function getUserSelectedLanguages($record) { + $user_languages = []; + + $result = $this->queryLogs("SELECT timestamp, message, record_id, language_value, instrument, event_id + WHERE message = ? AND record_id = ?", [ + "user_selected_language", + $record + ]); + + while($row = db_fetch_assoc($result)) { + $instrument = $row['instrument']; + $language_value = $row['language_value']; + $event_id = $row['event_id']; + + if (!empty($instrument) && !empty($language_value) && !empty($event_id)) { + if (empty($user_languages[$event_id])) { + $user_languages[$event_id] = []; + } + if (empty($user_languages[$event_id][$instrument])) { + $user_languages[$event_id][$instrument] = $language_value; + } + } + } + + return $user_languages; + } + + public function translatePDF(&$metadata, $user_languages) { + // translate survey instructions/titles + global $Proj; + $instruments = json_decode($this->getProjectSetting('instruments')); + if ($instruments && !empty($instruments)) { + foreach ($Proj->surveys as $id => &$survey) { + // determine which language to use for this form + $lang = ''; + $form_name = $survey['form_name']; + foreach($user_languages as $event_id => $event) { + if (!empty($event[$form_name])) { + $lang = $event[$form_name]; + break; + } + } + if ($lang == '') { + continue; + } + + if (!empty($instruments->$form_name->$lang->survey_settings->title)) { + $survey['title'] = $instruments->$form_name->$lang->survey_settings->title; + } + if (!empty($instruments->$form_name->$lang->survey_settings->acknowledgement)) { + $survey['instructions'] = $instruments->$form_name->$lang->survey_settings->acknowledgement; + } + } + } + + // translate field question/answer labels + foreach($metadata as &$field) { + // see which instrument this field belongs to + $parent_form = $field['form_name']; + $field_name = $field['field_name']; + + // get question and answer translations for this field + $translations = $this->getFieldTranslations($field); + + // determine which language to use for that field + $lang = ''; + foreach($user_languages as $event_id => $event) { + if (!empty($event[$parent_form])) { + $lang = $event[$parent_form]; + break; + } + } + if ($lang == '') { + continue; + } + + // determine the translated field label for this field/lang combo + if ($translations['lang'] && $translations['lang'][$lang]) { + $field['element_label'] = $translations['lang'][$lang]; + } + + // determine the translated answer labels for this field/lang combo + if ($translations['answers'] && $translations['answers'][$lang]) { + foreach($translations['answers'][$lang] as $raw => $translation) { + $translations['answers'][$lang][$raw] = "$raw, $translation"; + } + $field['element_enum'] = implode(" \\n ", $translations['answers'][$lang]); + } + } + + return $metadata; + } + + public function getFieldTranslations($field_array) { + // this function returns an array like: + /* + translations = [ + 'lang' => [ + 'English' => 'My Field Label', + 'Espanol' => 'Mi etiqueta de campo' + ], + 'answers' => [ + 'English' => [ + '0' => 'Zero', + '1' => 'One', + '2' => 'Two' + ], + 'Espanol' => [ + '0' => 'Cero', + '1' => 'Uno', + '2' => 'Dos' + ], + ] + ] + + assuming $field_array passed has 'misc' field with relevant @p1000lang and @p1000answers information + */ + $translations = []; + $field_misc = $field_array['misc']; + + // determine indexes for p1000lang and p1000answers + $regex_capture_p1000 = "/p1000([^{]*)/m"; + preg_match_all($regex_capture_p1000, $field_misc, $indexes); + $indexes = $indexes[1]; + + // capture pieces of field['misc'] that are contained in balanced curly braces (inclusive) + $regex_capture_balanced_braces = "/\{(?:[^}{]+|(?R))*+\}/m"; + preg_match_all($regex_capture_balanced_braces, $field_misc, $matches); + if (gettype($matches) == 'array') { + $matches = $matches[0]; + + // decode lang json (if applicable) + $lang_index = array_search('lang', $indexes, true); + if ($lang_index !== false) { + $translations['lang'] = json_decode($matches[$lang_index], true); + } + + // decode answers json (if applicable) + $answers_index = array_search('answers', $indexes, true); + if ($answers_index !== false) { + $translations['answers'] = json_decode($matches[$answers_index], true); + } + } + + return $translations; + } + +} +?> diff --git a/config.json b/config.json index f5a5c50..a202297 100644 --- a/config.json +++ b/config.json @@ -1,10 +1,14 @@ { - "name": "Multilingual", + "name": "Multilingual (deprecated)", "namespace": "CMH\\Multilingual", - "description": "Allow survey's and data entry forms to be translated into multiple languages. Add translations via the Online Designer.", + "description": "This module does not work properly in newer PHP versions, and has been deprecated in favor of REDCap's built-in Multi-Language Management feature. Allow survey's and data entry forms to be translated into multiple languages. Add translations via the Online Designer.", + "compatibility": { + "php-version-max": "7.99.99" + }, + "versions": [ {"1.2": "Move all functions into Multilingual class"}, {"1.3": "Fix matrix column label order"}, diff --git a/multilingualPDF.php b/multilingualPDF.php index 64008b8..6c8b427 100644 --- a/multilingualPDF.php +++ b/multilingualPDF.php @@ -44,7 +44,7 @@ function getName($n) { ob_end_clean(); //get metadata - $metadata = $module->getMetaData(intval(intval($_GET['pid'])), $_GET['form']); + $metadata = $module->getMetaData2(intval(intval($_GET['pid'])), $_GET['form']); //replace labels and element_enum with translations foreach($metadata AS $key => $values){