query("SELECT languageCode, name FROM language ORDER BY languageCode")->fetchAll(PDO::FETCH_ASSOC); qdb_discard($tmpDb, $lockFp); json_success(["languages" => $rows]); } if (!empty($_GET['all'])) { [$pdo, $tmpDb, $lockFp] = qdb_open(false); $languages = $pdo->query("SELECT languageCode, name FROM language ORDER BY languageCode")->fetchAll(PDO::FETCH_ASSOC); if (!array_filter($languages, fn($l) => $l['languageCode'] === QDB_SOURCE_LANGUAGE)) { array_unshift($languages, ['languageCode' => QDB_SOURCE_LANGUAGE, 'name' => 'German']); } $qnRows = $pdo->query(" SELECT questionnaireID, name, orderIndex FROM questionnaire ORDER BY orderIndex ")->fetchAll(PDO::FETCH_ASSOC); $appEntries = qdb_app_ui_string_entries_for_website(); $appTranslations = qdb_load_translations_for_entries($pdo, $appEntries); qdb_attach_translation_texts($appEntries, $appTranslations); $questionnaires = []; $allEntries = $appEntries; foreach ($qnRows as $qn) { $lists = qdb_translation_entry_lists($pdo, $qn['questionnaireID']); $entries = array_merge($lists['stringEntries'], $lists['contentEntries']); if (!$entries) { continue; } $translations = qdb_load_translations_for_entries($pdo, $entries); qdb_attach_translation_texts($entries, $translations); $questionnaires[] = [ 'questionnaireID' => $qn['questionnaireID'], 'name' => $qn['name'], 'orderIndex' => (int)$qn['orderIndex'], 'entries' => $entries, ]; foreach ($entries as $e) { $allEntries[] = $e; } } qdb_discard($tmpDb, $lockFp); json_success([ 'languages' => $languages, 'appStrings' => $appEntries, 'questionnaires' => $questionnaires, 'entries' => $allEntries, 'sourceLanguage' => QDB_SOURCE_LANGUAGE, ]); } $qnID = $_GET['questionnaireID'] ?? ''; if ($qnID) { [$pdo, $tmpDb, $lockFp] = qdb_open(false); $languages = $pdo->query("SELECT languageCode, name FROM language ORDER BY languageCode")->fetchAll(PDO::FETCH_ASSOC); if (!array_filter($languages, fn($l) => $l['languageCode'] === QDB_SOURCE_LANGUAGE)) { array_unshift($languages, ['languageCode' => QDB_SOURCE_LANGUAGE, 'name' => 'German']); } $qnRow = $pdo->prepare("SELECT name FROM questionnaire WHERE questionnaireID = :id"); $qnRow->execute([':id' => $qnID]); $qnName = $qnRow->fetchColumn() ?: ''; $lists = qdb_translation_entry_lists($pdo, $qnID); $entries = array_merge($lists['stringEntries'], $lists['contentEntries']); $translations = qdb_load_translations_for_entries($pdo, $entries); qdb_attach_translation_texts($entries, $translations); qdb_discard($tmpDb, $lockFp); json_success([ 'languages' => $languages, 'entries' => $entries, 'questionnaire' => ['questionnaireID' => $qnID, 'name' => $qnName], 'sourceLanguage' => QDB_SOURCE_LANGUAGE, ]); } $type = $_GET['type'] ?? ''; $id = $_GET['id'] ?? ''; if (!in_array($type, $validTypes, true) || (!$id && $type !== 'string')) { json_error('BAD_REQUEST', 'type (question|answer_option|string) and id required', 400); } [$pdo, $tmpDb, $lockFp] = qdb_open(false); if ($type === 'question') { $stmt = $pdo->prepare("SELECT languageCode, text FROM question_translation WHERE questionID = :id"); $stmt->execute([':id' => $id]); } elseif ($type === 'answer_option') { $stmt = $pdo->prepare("SELECT languageCode, text FROM answer_option_translation WHERE answerOptionID = :id"); $stmt->execute([':id' => $id]); } else { if ($id) { $stmt = $pdo->prepare("SELECT stringKey, languageCode, text FROM string_translation WHERE stringKey = :id"); $stmt->execute([':id' => $id]); } else { $stmt = $pdo->query("SELECT stringKey, languageCode, text FROM string_translation ORDER BY stringKey, languageCode"); } } $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); qdb_discard($tmpDb, $lockFp); json_success(["translations" => $rows]); break; case 'PUT': require_role(['admin', 'supervisor'], $tokenRec); $body = read_json_body(); $type = $body['type'] ?? ''; if ($type === 'language') { $lang = trim($body['languageCode'] ?? ''); $name = trim($body['name'] ?? ''); if (!$lang) { json_error('MISSING_FIELDS', 'languageCode required', 400); } [$pdo, $tmpDb, $lockFp] = qdb_open(true); try { if ($lang === QDB_SOURCE_LANGUAGE) { qdb_ensure_source_language($pdo); } else { $pdo->prepare("INSERT INTO language (languageCode, name) VALUES (:lc, :n) ON CONFLICT(languageCode) DO UPDATE SET name = excluded.name") ->execute([':lc' => $lang, ':n' => $name]); } qdb_save($tmpDb, $lockFp); json_success([]); } catch (Throwable $e) { qdb_discard($tmpDb, $lockFp); error_log($e->getMessage()); json_error('SERVER_ERROR', 'Server error', 500); } break; } $id = $body['id'] ?? ''; $lang = trim($body['languageCode'] ?? ''); $text = $body['text'] ?? ''; if (!in_array($type, $validTypes, true) || !$id || !$lang) { json_error('MISSING_FIELDS', 'type, id, and languageCode required', 400); } [$pdo, $tmpDb, $lockFp] = qdb_open(true); try { qdb_put_translation($pdo, $type, $id, $lang, $text); qdb_save($tmpDb, $lockFp); json_success([]); } catch (Throwable $e) { qdb_discard($tmpDb, $lockFp); error_log($e->getMessage()); json_error('SERVER_ERROR', 'Server error', 500); } break; case 'DELETE': require_role(['admin', 'supervisor'], $tokenRec); $body = read_json_body(); $type = $body['type'] ?? ''; if ($type === 'language') { $lang = trim($body['languageCode'] ?? ''); if (!$lang) { json_error('MISSING_FIELDS', 'languageCode required', 400); } if ($lang === QDB_SOURCE_LANGUAGE) { json_error('BAD_REQUEST', 'German (de) cannot be removed', 400); } [$pdo, $tmpDb, $lockFp] = qdb_open(true); try { $pdo->prepare("DELETE FROM language WHERE languageCode = :lc")->execute([':lc' => $lang]); $pdo->prepare("DELETE FROM question_translation WHERE languageCode = :lc")->execute([':lc' => $lang]); $pdo->prepare("DELETE FROM answer_option_translation WHERE languageCode = :lc")->execute([':lc' => $lang]); $pdo->prepare("DELETE FROM string_translation WHERE languageCode = :lc")->execute([':lc' => $lang]); qdb_save($tmpDb, $lockFp); json_success([]); } catch (Throwable $e) { qdb_discard($tmpDb, $lockFp); error_log($e->getMessage()); json_error('SERVER_ERROR', 'Server error', 500); } break; } $id = $body['id'] ?? ''; $lang = trim($body['languageCode'] ?? ''); if (!in_array($type, $validTypes, true) || !$id || !$lang) { json_error('MISSING_FIELDS', 'type, id, and languageCode required', 400); } [$pdo, $tmpDb, $lockFp] = qdb_open(true); try { if ($type === 'question') { $pdo->prepare("DELETE FROM question_translation WHERE questionID = :id AND languageCode = :lang") ->execute([':id' => $id, ':lang' => $lang]); } elseif ($type === 'answer_option') { $pdo->prepare("DELETE FROM answer_option_translation WHERE answerOptionID = :id AND languageCode = :lang") ->execute([':id' => $id, ':lang' => $lang]); } else { $pdo->prepare("DELETE FROM string_translation WHERE stringKey = :id AND languageCode = :lang") ->execute([':id' => $id, ':lang' => $lang]); } qdb_save($tmpDb, $lockFp); json_success([]); } catch (Throwable $e) { qdb_discard($tmpDb, $lockFp); error_log($e->getMessage()); json_error('SERVER_ERROR', 'Server error', 500); } break; default: json_error('METHOD_NOT_ALLOWED', 'Method not allowed', 405); }