Initial backend translation support

This commit is contained in:
Matteo Gheza 2022-03-19 00:29:27 +01:00
parent db2c475e5c
commit 0b6251767e
5 changed files with 212 additions and 31 deletions

View File

@ -93,7 +93,7 @@ function updateAlertMessages($alert, $crew=null, $alertDeleted = false) {
if(!is_null($message_id) && !is_null($chat_id)) {
$Bot->sendMessage([
"chat_id" => $chat_id,
"text" => "Allerta rimossa.\nPartecipazione non più richiesta.",
"text" => __("alerts.alert_removed"),
"reply_to_message_id" => $message_id
]);
try {
@ -160,7 +160,7 @@ function updateAlertMessages($alert, $crew=null, $alertDeleted = false) {
if((!is_null($message_id) || !is_null($chat_id)) && $member["response"] === "waiting") {
$Bot->sendMessage([
"chat_id" => $chat_id,
"text" => "Numero minimo vigili richiesti raggiunto.\nPartecipazione non più richiesta.",
"text" => __("alerts.alert_completed"),
"reply_to_message_id" => $message_id
]);
try {
@ -192,7 +192,7 @@ function setAlertResponse($response, $userId, $alertId) {
if(!$alert["enabled"]) return;
$crew = json_decode($alert["crew"], true);
$messageText = $response ? "🟢 Partecipazione accettata." : "🔴 Partecipazione rifiutata.";
$messageText = $response ? __("alerts.accepted") : __("alerts.rejected");
foreach($crew as &$member) {
if($member["id"] == $userId) {
@ -272,20 +272,20 @@ function alertsRouter (FastRoute\RouteCollector $r) {
requireLogin();
$users->online_time_update();
if(!$users->hasRole(Role::SUPER_EDITOR)) {
apiResponse(["status" => "error", "message" => "Access denied"]);
apiResponse(["status" => "error", "message" => __("access_denied")]);
return;
}
try {
$crew_members = callsList($_POST["type"]);
} catch (NoChiefAvailableException) {
apiResponse(["status" => "error", "message" => "Nessun caposquadra disponibile. Contattare i vigili manualmente."]);
apiResponse(["status" => "error", "message" => __("alerts.no_chief_available")]);
return;
} catch (NoDriverAvailableException) {
apiResponse(["status" => "error", "message" => "Nessun autista disponibile. Contattare i vigili manualmente."]);
apiResponse(["status" => "error", "message" => __("alerts.no_drivers_available")]);
return;
} catch (NotEnoughAvailableUsersException) {
apiResponse(["status" => "error", "message" => "Nessun utente disponibile. Distaccamento non operativo."]);
apiResponse(["status" => "error", "message" => __("alerts.not_enough_available_users")]);
return;
}
@ -340,7 +340,7 @@ function alertsRouter (FastRoute\RouteCollector $r) {
requireLogin();
$alert = $db->selectRow("SELECT * FROM `".DB_PREFIX."_alerts` WHERE `id` = :id", [":id" => $vars["id"]]);
if(is_null($alert)) {
apiResponse(["error" => "alert not found"]);
apiResponse(["error" => __("alerts.alert_not_found")]);
return;
}
$alert["crew"] = json_decode($alert["crew"], true);
@ -359,7 +359,7 @@ function alertsRouter (FastRoute\RouteCollector $r) {
requireLogin();
$users->online_time_update();
if(!$users->hasRole(Role::SUPER_EDITOR)) {
apiResponse(["status" => "error", "message" => "Access denied"]);
apiResponse(["status" => "error", "message" => __("access_denied")]);
return;
}
$db->update(
@ -390,7 +390,7 @@ function alertsRouter (FastRoute\RouteCollector $r) {
requireLogin();
$users->online_time_update();
if(!$users->hasRole(Role::SUPER_EDITOR)) {
apiResponse(["status" => "error", "message" => "Access denied"]);
apiResponse(["status" => "error", "message" => __("access_denied")]);
return;
}
$db->update(

View File

@ -274,7 +274,7 @@ function apiRouter (FastRoute\RouteCollector $r) {
$users->online_time_update();
if(!$users->hasRole(Role::SUPER_EDITOR) && (int) $_POST["id"] !== $users->auth->getUserId()){
statusCode(401);
apiResponse(["status" => "error", "message" => "You don't have permission to change other users availability", "t" => $users->auth->getUserId()]);
apiResponse(["status" => "error", "message" => __("other_user_availability_change_forbidden"), "t" => $users->auth->getUserId()]);
return;
}
$user_id = is_numeric($_POST["id"]) ? $_POST["id"] : $users->auth->getUserId();
@ -383,32 +383,32 @@ function apiRouter (FastRoute\RouteCollector $r) {
global $users;
try {
$token = $users->loginAndReturnToken($_POST["username"], $_POST["password"]);
logger("Login effettuato");
logger(__("log_messages.new_login"));
apiResponse(["status" => "success", "access_token" => $token]);
}
catch (\Delight\Auth\InvalidEmailException $e) {
statusCode(401);
apiResponse(["status" => "error", "message" => "Wrong email address"]);
apiResponse(["status" => "error", "message" => __("login.wrong_email")]);
}
catch (\Delight\Auth\InvalidPasswordException $e) {
statusCode(401);
apiResponse(["status" => "error", "message" => "Wrong password"]);
apiResponse(["status" => "error", "message" => __("login.wrong_password")]);
}
catch (\Delight\Auth\EmailNotVerifiedException $e) {
statusCode(401);
apiResponse(["status" => "error", "message" => "Email not verified"]);
apiResponse(["status" => "error", "message" => __("login.email_not_confirmed")]);
}
catch (\Delight\Auth\UnknownUsernameException $e) {
statusCode(401);
apiResponse(["status" => "error", "message" => "Wrong username"]);
apiResponse(["status" => "error", "message" => __("login.wrong_username")]);
}
catch (\Delight\Auth\TooManyRequestsException $e) {
statusCode(401);
apiResponse(["status" => "error", "message" => "Too many requests"]);
apiResponse(["status" => "error", "message" => __("too_many_requests")]);
}
catch (Exception $e) {
statusCode(401);
apiResponse(["status" => "error", "message" => "Unknown error", "error" => $e]);
apiResponse(["status" => "error", "message" => __("unknown_error"), "error" => $e]);
}
}
);
@ -421,7 +421,7 @@ function apiRouter (FastRoute\RouteCollector $r) {
if(!$users->hasRole(Role::SUPER_ADMIN)) {
statusCode(401);
apiResponse(["status" => "error", "message" => "You don't have permission to impersonate"]);
apiResponse(["status" => "error", "message" => __("impersonate_user_forbidden")]);
return;
}
@ -431,15 +431,15 @@ function apiRouter (FastRoute\RouteCollector $r) {
}
catch (\Delight\Auth\UnknownIdException $e) {
statusCode(400);
apiResponse(["status" => "error", "message" => "Wrong user ID"]);
apiResponse(["status" => "error", "message" => __("login.wrong_userid")]);
}
catch (\Delight\Auth\EmailNotVerifiedException $e) {
statusCode(400);
apiResponse(["status" => "error", "message" => "Email not verified"]);
apiResponse(["status" => "error", "message" => __("login.email_not_confirmed")]);
}
catch (Exception $e) {
statusCode(400);
apiResponse(["status" => "error", "message" => "Unknown error", "error" => $e]);
apiResponse(["status" => "error", "message" => __("unknown_error"), "error" => $e]);
}
}
);

View File

@ -0,0 +1,49 @@
<?php
return [
"log_messages" => [
//TODO: save logs as translation string in DB, then translate it when serving them
//(and return empty string if translation is not found)
"new_login" => "New login",
"availability_schedules_updated" => "Availability schedules updated",
"user_added" => "User added",
"user_updated" => "User updated",
"user_removed" => "User removed",
"service_added" => "Service added",
"service_updated" => "Service updated",
"service_removed" => "Service removed",
"training_added" => "Training added",
"training_updated" => "Training updated",
"training_removed" => "Training removed",
"availability_changed_to" => "Availability changed to \"%s\"",
],
"login" => [
"wrong_email" => "Wrong email",
"wrong_password" => "Wrong password",
"wrong_username" => "Wrong username",
"wrong_userid" => "Wrong userid",
"email_not_confirmed" => "Email not confirmed"
],
"alerts" => [
"alert_removed" => "Alerta removed.\\nAvailability not requested anymore.",
"alert_completed" => "Minimum number of members required reached.\\nParticipation not requested anymore.",
"accepted" => "🟢 Accepted.",
"rejected" => "🔴 Reject.",
"no_chief_available" => "No chief available. Contact the members manually.",
"no_driver_available" => "No driver available. Contact the members manually.",
"not_enough_users_available" => "Not enough users available. Contact the members manually.",
"alert_not_found" => "Alert not found",
],
"telegram_bot" => [
//TODO: select Telegram bot language from user's language
"available_support" => "🧯 Available for support",
"available_full" => "🚒 Available with full team",
"not_available" => "⚠️ Not available"
],
"other_user_availability_change_forbidden" => "You don't have permission to change other users availability",
"impersonate_user_forbidden" => "You don't have permission to impersonate other users",
"too_many_requests" => "Too many requests",
"unknown_error" => "Unknown error",
"access_denied" => "Access denied",
"available" => "available",
"not_available" => "not available",
];

View File

@ -0,0 +1,46 @@
<?php
return [
"log_messages" => [
"new_login" => "Nuovo accesso",
"availability_schedules_updated" => "Programmazione disponibilità aggiornata",
"user_added" => "Utente aggiunto",
"user_updated" => "Utente aggiornato",
"user_removed" => "Utente rimosso",
"service_added" => "Servizio aggiunto",
"service_updated" => "Servizio aggiornato",
"service_removed" => "Servizio rimosso",
"training_added" => "Esercitazione aggiunta",
"training_updated" => "Esercitazione aggiornata",
"training_removed" => "Esercitazione rimossa",
"availability_changed_to" => "Disponibilità cambiata a \"%s\"",
],
"login" => [
"wrong_email" => "Email errata",
"wrong_password" => "Password errata",
"wrong_username" => "Nome utente errato",
"wrong_userid" => "ID utente errato",
"email_not_confirmed" => "Email non confermata"
],
"alerts" => [
"alert_removed" => "Allerta rimossa.\\nDisponibilità non più richiesta.",
"alert_completed" => "Numero minimo vigili richiesti raggiunto.\nPartecipazione non più richiesta.",
"accepted" => "🟢 Partecipazione accettata.",
"rejected" => "🔴 Partecipazione rifiutata.",
"no_chief_available" => "Nessun caposquadra disponibile. Contattare i vigili manualmente.",
"no_driver_available" => "Nessun autista disponibile. Contattare i vigili manualmente.",
"not_enough_users_available" => "Non ci sono abbastanza utenti disponibili. Contattare i vigili manualmente.",
"alert_not_found" => "Allerta non trovata",
],
"telegram_bot" => [
"available_support" => "🧯 Distaccamento operativo per supporto",
"available_full" => "🚒 Distaccamento operativo con squadra completa",
"not_available" => "⚠️ Distaccamento non operativo"
],
"other_user_availability_change_forbidden" => "Non hai il permesso di cambiare la disponibilità di altri utenti",
"impersonate_user_forbidden" => "Non hai il permesso di impersonare altri utenti",
"too_many_requests" => "Troppe richieste",
"unknown_error" => "Errore sconosciuto",
"access_denied" => "Accesso negato",
"available" => "disponibile",
"not_available" => "non disponibile",
];

View File

@ -196,7 +196,7 @@ class Users
if($chief == 1) {
$this->auth->admin()->addRoleForUserById($userId, Role::SUPER_EDITOR);
}
logger("User added", $userId, $inserted_by);
logger(__("log_messages.user_created"), $userId, $inserted_by);
return $userId;
} else {
return false;
@ -223,7 +223,7 @@ class Users
DB_PREFIX."_profiles",
["id" => $id]
);
logger("User removed", null, $removed_by);
logger(__("log_messages.user_removed"), null, $removed_by);
}
public function online_time_update($id=null){
@ -336,7 +336,7 @@ class Availability {
public function change($availability, $user_id, $is_manual_mode=true)
{
if($is_manual_mode) logger("Disponibilità cambiata in ".($availability ? '"disponibile"' : '"non disponibile"'), $user_id, $this->users->auth->getUserId());
if($is_manual_mode) logger(sprintf(__("availability_changed_to"), __($availability ? 'available' : 'not_available')), $user_id, $this->users->auth->getUserId());
$change_values = ["available" => $availability];
if($is_manual_mode) $change_values["manual_mode"] = 1;
@ -350,11 +350,11 @@ class Availability {
if(!$this->users->isHidden($user_id)) {
$available_users_count = $this->db->selectValue("SELECT COUNT(id) FROM `".DB_PREFIX."_profiles` WHERE `available` = 1 AND `hidden` = 0");
if($available_users_count === 5) {
sendTelegramNotification("🚒 Distaccamento operativo con squadra completa");
sendTelegramNotification(__("telegram_bot.available_full"));
} else if($available_users_count < 2) {
sendTelegramNotification("⚠️ Distaccamento non operativo");
sendTelegramNotification(__("telegram_bot.not_available"));
} else if($available_users_count < 5) {
sendTelegramNotification("🧯 Distaccamento operativo per supporto");
sendTelegramNotification(__("telegram_bot.available_support"));
}
}
@ -454,7 +454,7 @@ class Services {
$serviceId = $this->db->getLastInsertId();
$this->increment_counter($chief.",".$drivers.",".$crew);
logger("Service added");
logger(__("log_messages.service_added"));
return $serviceId;
}
@ -471,7 +471,7 @@ class Services {
DB_PREFIX."_services",
["id" => $id]
);
logger("Intervento eliminato");
logger(__("log_messages.service_deleted"));
return true;
}
@ -610,7 +610,7 @@ class Schedules {
public function update($schedules, $profile="default") {
//TODO implement multiple profiles
//TODO implement holidays
logger("Aggiornata programmazione orari disponibilità");
logger(__("log_messages.availability_schedules_updated"));
if(empty($this->get($profile))) {
return $this->db->insert(
DB_PREFIX."_schedules",
@ -626,8 +626,94 @@ class Schedules {
}
}
class Translations
{
public $loaded_languages = ["en", "it"];
public $default_language = "en";
public $language = null;
public $client_languages = ["en"];
public $loaded_translations = [];
public $filename = "";
public function client_languages()
{
if(isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
$client_languages = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
} else {
$client_languages = "en-US;q=0.5,en;q=0.3";
}
if(strpos($client_languages, ';') == false) {
if(strpos($client_languages, '-') !== false) {
return [substr($client_languages, 0, 5)];
} else {
return [substr($client_languages, 0, 2)];
}
} else {
$client_languages = explode(",", $client_languages);
$tmp_languages = [];
foreach($client_languages as $language){
if(strpos($language, ';') == false) {
$tmp_languages[$language] = 1;
} else {
$tmp_languages[explode(";q=", $language)[0]] = (float) explode(";q=", $language)[1];
}
}
arsort($tmp_languages);
return array_keys($tmp_languages);
}
}
public function __construct($force_language = false)
{
$this->client_languages = $this->client_languages();
if(isset($_COOKIE["forceLanguage"]) && in_array($_COOKIE["forceLanguage"], $this->loaded_languages)){
$this->language = $_COOKIE["forceLanguage"];
} else if($force_language && in_array($force_language, $this->loaded_languages)){
$this->language = $force_language;
} else {
foreach($this->client_languages as $language){
if(in_array($language, $this->loaded_languages) && $this->language == null) {
$this->language = $language;
}
}
if($this->language == null) {
$this->language = "en";
}
}
$this->filename = "translations/".$this->language.".php";
if (file_exists($this->filename)) {
$this->loaded_translations = require($this->filename);
} else {
throw new Exception("Language file not found");
}
}
public function translate($string)
{
if(strpos($string, ".") !== false) {
$string = explode(".", $string);
if (!array_key_exists($string[1], $this->loaded_translations[$string[0]])) {
throw new Exception('string does not exist');
}
return $this->loaded_translations[$string[0]][$string[1]];
} else {
if (!array_key_exists($string, $this->loaded_translations)) {
throw new Exception('string does not exist');
}
return $this->loaded_translations[$string];
}
}
}
$users = new Users($db, $auth);
$availability = new Availability($db, $users);
$places = new Places($cache, $users, $db);
$services = new Services($db, $users, $places);
$schedules = new Schedules($db, $users);
$translations = new Translations();
function __(string $string)
{
global $translations;
return $translations->translate($string);
}